diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java index f667a75825..a52053f6d8 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddImageTask.java @@ -114,7 +114,7 @@ class AddImageTask implements Runnable { List errorMessages = new ArrayList<>(); List newDataSources = new ArrayList<>(); try { - currentCase.getSleuthkitCase().acquireExclusiveLock(); + currentCase.getSleuthkitCase().acquireSingleUserCaseWriteLock(); synchronized (tskAddImageProcessLock) { if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true, @@ -132,7 +132,7 @@ class AddImageTask implements Runnable { commitOrRevertAddImageProcess(currentCase, errorMessages, newDataSources); progressMonitor.setProgress(100); } finally { - currentCase.getSleuthkitCase().releaseExclusiveLock(); + currentCase.getSleuthkitCase().releaseSingleUserCaseWriteLock(); DataSourceProcessorCallback.DataSourceProcessorResult result; if (criticalErrorOccurred) { result = DataSourceProcessorResult.CRITICAL_ERRORS; diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties index 0dd66e8c59..4cca7e78d6 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties @@ -1,16 +1,23 @@ OptionsCategory_Name_TagNamesOptions=Tags OptionsCategory_TagNames=TagNames Blackboard.unableToIndexArtifact.error.msg=Unable to index blackboard artifact {0} -NewTagNameDialog.title.text=New Tag Name -NewTagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; -NewTagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name -NewTagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty -NewTagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name +TagNameDialog.title.text=New Tag +TagNameDialog.JOptionPane.tagNameIllegalCharacters.message=Tag name may not contain any of the following symbols\: \\ \: * ? " < > | , ; +TagNameDialog.JOptionPane.tagNameIllegalCharacters.title=Invalid character in tag name +TagNameDialog.JOptionPane.tagNameEmpty.message=The tag name cannot be empty +TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name 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. -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 +TagOptionsPanel.deleteTagNameButton.text=Delete Tag +TagOptionsPanel.newTagNameButton.text=New Tag +TagOptionsPanel.editTagNameButton.text=Edit Tag +TagNameDialog.descriptionLabel.text=Description: +TagNameDialog.okButton.text=OK +TagNameDialog.cancelButton.text=Cancel +TagNameDialog.tagNameTextField.text= +TagNameDialog.newTagNameLabel.text=Name: +TagNameDialog.notableCheckbox.text=Tag indicates item is notable. +TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: +TagOptionsPanel.notableYesOrNoLabel.text= +TagOptionsPanel.descriptionLabel.text=Tag Description: +TagOptionsPanel.jTextArea1.text=Create and manage tags, which can be applied to files and results in the case. Notable tags will cause items tagged with them to be flagged as notable when using a central repository. +TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running! 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 a27e3ca586..41e871691b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties @@ -1,2 +1,3 @@ TagsManager.predefTagNames.bookmark.text=\u30d6\u30c3\u30af\u30de\u30fc\u30af -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 +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 +TagOptionsPanel.ingestRunningWarningLabel.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u3092\u5b9f\u884c\u4e2d\u306b\u30d5\u30a1\u30a4\u30eb\u30bf\u30a4\u30d7\u5b9a\u7fa9\u3092\u5909\u66f4\u3067\u304d\u307e\u305b\u3093\uff01 diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java new file mode 100755 index 0000000000..096f3cad69 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefinition.java @@ -0,0 +1,306 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011-2017 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.HashSet; +import java.util.List; +import java.util.Objects; +import java.util.Set; +import java.util.logging.Level; +import javax.annotation.concurrent.Immutable; +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.TagName; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; +import org.sleuthkit.datamodel.SleuthkitCase; +import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; + +/** + * A tag name definition consisting of a display name, description and color. + */ +@Immutable +final class TagNameDefinition implements Comparable { + + private static final Logger LOGGER = Logger.getLogger(TagNameDefinition.class.getName()); + @NbBundle.Messages({"TagNameDefinition.predefTagNames.bookmark.text=Bookmark", + "TagNameDefinition.predefTagNames.followUp.text=Follow Up", + "TagNameDefinition.predefTagNames.notableItem.text=Notable Item"}) + private static final String TAGS_SETTINGS_NAME = "Tags"; //NON-NLS + private static final String TAG_NAMES_SETTING_KEY = "TagNames"; //NON-NLS + + private static final List STANDARD_NOTABLE_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(), DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName()); // NON-NLS + private static final List STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefinition_predefTagNames_bookmark_text(), Bundle.TagNameDefinition_predefTagNames_followUp_text(), + Bundle.TagNameDefinition_predefTagNames_notableItem_text(), DhsImageCategory.ONE.getDisplayName(), + DhsImageCategory.TWO.getDisplayName(), DhsImageCategory.THREE.getDisplayName(), + DhsImageCategory.FOUR.getDisplayName(), DhsImageCategory.FIVE.getDisplayName()); + private final String displayName; + private final String description; + private final TagName.HTML_COLOR color; + private final TskData.FileKnown knownStatus; + + /** + * Constructs a tag name definition consisting of a display name, + * description, color and knownStatus. + * + * @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. + * @param knownStatus The status denoted by the tag name. + */ + TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { + this.displayName = displayName; + this.description = description; + this.color = color; + this.knownStatus = status; + } + + static List getStandardTagNames() { + return STANDARD_TAG_DISPLAY_NAMES; + } + + /** + * Gets the display name for the tag name. + * + * @return The display name. + */ + String getDisplayName() { + return displayName; + } + + /** + * Gets the description for the tag name. + * + * @return The description. + */ + String getDescription() { + return description; + } + + /** + * Gets the color for the tag name. + * + * @return The color. + */ + TagName.HTML_COLOR getColor() { + return color; + } + + /** + * Whether or not the status that this tag implies Notable status + * + * @return true if the Notable status is implied by this tag, false + * otherwise. + */ + boolean isNotable() { + return knownStatus == TskData.FileKnown.BAD; + } + + /** + * Compares this tag name definition with the specified tag name definition + * for order. + * + * @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 name definition is less than, equal to, or greater than + * the specified tag name definition. + */ + @Override + public int compareTo(TagNameDefinition other) { + return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); + } + + /** + * Returns a hash code value for this tag name definition. + * + * @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 name + * definition. + * + * @param obj The object to test for equality. + * + * @return True or false. + */ + @Override + public boolean equals(Object obj) { + if (!(obj instanceof TagNameDefinition)) { + return false; + } + TagNameDefinition thatTagName = (TagNameDefinition) obj; + return this.getDisplayName().equals(thatTagName.getDisplayName()); + } + + /** + * A string representation of this tag name definition. + * + * @return The display name of the tag type. + */ + @Override + public String toString() { + return displayName; + } + + /** + * @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() + "," + knownStatus.toString(); + } + + private TagName saveToCase(SleuthkitCase caseDb) { + TagName tagName = null; + try { + tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); + } catch (TskCoreException ex) { + LOGGER.log(Level.SEVERE, "Error updating non-file object ", ex); + } + return tagName; + } + + /** + * Gets tag name definitions from the tag settings file as well as the + * default tag name definitions. + * + * @return A set of tag name definition objects. + */ + static synchronized Set getTagNameDefinitions() { + Set tagNames = new HashSet<>(); + //modifiable copy of default tags list for us to keep track of which default tags have already been created + Set standardTags = new HashSet<>(STANDARD_TAG_DISPLAY_NAMES); + String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY); + if (null != setting && !setting.isEmpty()) { + List tagNameTuples = Arrays.asList(setting.split(";")); + int numberOfAttributes = 0; + if (tagNameTuples.size() > 0) { + // Determine if Tags.properties file needs to be upgraded + numberOfAttributes = tagNameTuples.get(0).split(",").length; + } + if (numberOfAttributes == 3) { + // Upgrade Tags.Properties with the settings in Central Repository Settings if necessary + tagNames.addAll(upgradeTagPropertiesFile(tagNameTuples, standardTags)); + } else if (numberOfAttributes == 4) { + // if the Tags.Properties file is up to date parse it + tagNames.addAll(readCurrentTagPropertiesFile(tagNameTuples, standardTags)); + } + } + //create standard tags which should always exist which were not already created for whatever reason, such as upgrade + for (String standardTagName : standardTags) { + if (STANDARD_NOTABLE_TAG_DISPLAY_NAMES.contains(standardTagName)) { + tagNames.add(new TagNameDefinition(standardTagName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.BAD)); + } else { + tagNames.add(new TagNameDefinition(standardTagName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN)); + } + } + return tagNames; + + } + + /** + * Read the central repository properties file to get any knownStatus + * related tag settings that may exist in it. + * + * @param tagProperties the list of comma seperated tags in the + * Tags.properties file + * @param standardTagsToBeCreated the list of standard tags which have yet + * to be created + * + * @return tagNames a list of TagNameDefinitions + */ + private static Set upgradeTagPropertiesFile(List tagProperties, Set standardTagsToBeCreated) { + Set tagNames = new HashSet<>(); + List legacyNotableTags = new ArrayList<>(); + String badTagsStr = ModuleSettings.getConfigSetting("CentralRepository", "db.badTags"); // NON-NLS + if (badTagsStr == null || badTagsStr.isEmpty()) { //if there were no bad tags in the central repo properties file use the default list + legacyNotableTags.addAll(STANDARD_NOTABLE_TAG_DISPLAY_NAMES); + } else { //otherwise use the list that was in the central repository properties file + legacyNotableTags.addAll(Arrays.asList(badTagsStr.split(","))); + } + for (String tagNameTuple : tagProperties) { + String[] tagNameAttributes = tagNameTuple.split(","); //get the attributes + standardTagsToBeCreated.remove(tagNameAttributes[0]); //remove the tag from the list of standard tags which have not been created + if (legacyNotableTags.contains(tagNameAttributes[0])) { //if tag should be notable mark create it as such + tagNames.add(new TagNameDefinition(tagNameAttributes[0], tagNameAttributes[1], + TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.BAD)); + } else { //otherwise create it as unknown + tagNames.add(new TagNameDefinition(tagNameAttributes[0], tagNameAttributes[1], + TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.UNKNOWN)); //add the default value for that tag + } + } + return tagNames; + } + + /** + * Read the Tags.properties file to get the TagNameDefinitions that are + * preserved accross cases. + * + * @param tagProperties the list of comma seperated tags in the + * Tags.properties file + * @param standardTagsToBeCreated the list of standard tags which have yet + * to be created + * + * @return tagNames a list of TagNameDefinitions + */ + private static Set readCurrentTagPropertiesFile(List tagProperties, Set standardTagsToBeCreated) { + Set tagNames = new HashSet<>(); + for (String tagNameTuple : tagProperties) { + String[] tagNameAttributes = tagNameTuple.split(","); //get the attributes + standardTagsToBeCreated.remove(tagNameAttributes[0]); //remove the tag from the list of standard tags which have not been created + tagNames.add(new TagNameDefinition(tagNameAttributes[0], tagNameAttributes[1], + TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.valueOf(tagNameAttributes[3]))); + } + return tagNames; + } + + /** + * Sets the tag name definitions in the tag settings file. + * + * @param tagNames A set of tag name definition objects. + */ + static synchronized void setTagNameDefinitions(Set tagNames) { + StringBuilder setting = new StringBuilder(); + for (TagNameDefinition tagName : tagNames) { + if (setting.length() != 0) { + setting.append(";"); + } + setting.append(tagName.toSettingsFormat()); + if (Case.isCaseOpen()) { + SleuthkitCase caseDb = Case.getCurrentCase().getSleuthkitCase(); + tagName.saveToCase(caseDb); + } + } + ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString()); + } + +} diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java deleted file mode 100755 index 101d68fa4c..0000000000 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java +++ /dev/null @@ -1,180 +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.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 name definition consisting of a display name, description and color. - */ -@Immutable -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 - private final String displayName; - private final String description; - private final TagName.HTML_COLOR color; - - /** - * Constructs a tag name definition consisting of a display name, - * description and color. - * - * @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. - */ - TagNameDefiniton(String displayName, String description, TagName.HTML_COLOR color) { - this.displayName = displayName; - this.description = description; - this.color = color; - } - - /** - * Gets the display name for the tag name. - * - * @return The display name. - */ - String getDisplayName() { - return displayName; - } - - /** - * Gets the description for the tag name. - * - * @return The description. - */ - String getDescription() { - return description; - } - - /** - * Gets the color for the tag name. - * - * @return The color. - */ - TagName.HTML_COLOR getColor() { - return color; - } - - /** - * Compares this tag name definition with the specified tag name definition - * for order. - * - * @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 name definition is less than, equal to, or greater than - * the specified tag name definition. - */ - @Override - public int compareTo(TagNameDefiniton other) { - return this.getDisplayName().toLowerCase().compareTo(other.getDisplayName().toLowerCase()); - } - - /** - * Returns a hash code value for this tag name definition. - * - * @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 name - * definition. - * - * @param obj The object to test for equality. - * - * @return True or false. - */ - @Override - public boolean equals(Object obj) { - if (!(obj instanceof TagNameDefiniton)) { - return false; - } - TagNameDefiniton thatTagName = (TagNameDefiniton) obj; - return this.getDisplayName().equals(thatTagName.getDisplayName()); - } - - /** - * A string representation of this tag name definition. - * - * @return The display name of the tag type. - */ - @Override - public String toString() { - return displayName; - } - - /** - * @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 tag name definitions from the tag settings file. - * - * @return A set of tag name definition objects. - */ - 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(","); - tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]))); - } - } - return tagNames; - } - - /** - * Sets the tag name definitions in the tag settings file. - * - * @param tagNames A set of tag name definition objects. - */ - static synchronized void setTagNameDefinitions(Set tagNames) { - StringBuilder setting = new StringBuilder(); - for (TagNameDefiniton tagName : tagNames) { - if (setting.length() != 0) { - setting.append(";"); - } - 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/NewTagNameDialog.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form similarity index 57% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.form rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form index b6400b7c31..e8162e6b3b 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.form @@ -23,10 +23,10 @@ - + - + @@ -34,6 +34,14 @@ + + + + + + + + @@ -41,20 +49,22 @@ - + - - - - + + + + + + + - @@ -63,21 +73,21 @@ - + - + - + @@ -87,12 +97,44 @@ - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java similarity index 62% rename from Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java index ff21ac283b..36ed5aeaaa 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java @@ -1,7 +1,7 @@ /* * Autopsy Forensic Browser * -* Copyright 2011-2016 Basis Technology Corp. +* Copyright 2011-2017 Basis Technology Corp. * Contact: carrier sleuthkit org * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -28,11 +28,14 @@ import javax.swing.JOptionPane; import javax.swing.event.DocumentEvent; import javax.swing.event.DocumentListener; import org.openide.util.NbBundle; +import org.openide.util.NbBundle.Messages; -final class NewTagNameDialog extends javax.swing.JDialog { +final class TagNameDialog extends javax.swing.JDialog { private static final long serialVersionUID = 1L; private String userTagDisplayName; + private String userTagDescription; + private boolean userTagIsNotable; private BUTTON_PRESSED result; enum BUTTON_PRESSED { @@ -42,13 +45,25 @@ final class NewTagNameDialog extends javax.swing.JDialog { /** * Creates a new NewUserTagNameDialog dialog. */ - NewTagNameDialog() { - super(new JFrame(NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.title.text")), - NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.title.text"), true); + TagNameDialog() { + super(new JFrame(NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.title.text")), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.title.text"), true); initComponents(); this.display(); } + @Messages({"TagNameDialog.editTitle.text=Edit Tag"}) + TagNameDialog(TagNameDefinition tagNameToEdit) { + super(new JFrame(NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.editTitle.text")), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.editTitle.text"), true); + initComponents(); + tagNameTextField.setText(tagNameToEdit.getDisplayName()); + descriptionTextArea.setText(tagNameToEdit.getDescription()); + notableCheckbox.setSelected(tagNameToEdit.isNotable()); + tagNameTextField.setEnabled(false); + this.display(); + } + /** * Sets display settings for the dialog and adds appropriate listeners. */ @@ -56,7 +71,7 @@ final class NewTagNameDialog extends javax.swing.JDialog { setLayout(new BorderLayout()); /* - * Center the dialog + * Center the dialog */ Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); int width = this.getSize().width; @@ -81,14 +96,17 @@ final class NewTagNameDialog extends javax.swing.JDialog { public void changedUpdate(DocumentEvent e) { fire(); } + @Override public void removeUpdate(DocumentEvent e) { fire(); } + @Override public void insertUpdate(DocumentEvent e) { fire(); } + private void fire() { enableOkButton(); } @@ -105,6 +123,7 @@ final class NewTagNameDialog extends javax.swing.JDialog { /** * 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) { @@ -112,38 +131,49 @@ final class NewTagNameDialog extends javax.swing.JDialog { String newTagDisplayName = tagNameTextField.getText().trim(); if (newTagDisplayName.isEmpty()) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.JOptionPane.tagNameEmpty.message"), - NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.JOptionPane.tagNameEmpty.title"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.message"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.title"), JOptionPane.ERROR_MESSAGE); return; - } - if (TagsManager.containsIllegalCharacters(newTagDisplayName)) { + } + //if a tag name contains illegal characters and is not the name of one of the standard tags + if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefinition.getStandardTagNames().contains(newTagDisplayName)) { JOptionPane.showMessageDialog(null, - NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), - NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), + NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), JOptionPane.ERROR_MESSAGE); return; } + userTagDescription = descriptionTextArea.getText(); userTagDisplayName = newTagDisplayName; + userTagIsNotable = notableCheckbox.isSelected(); result = BUTTON_PRESSED.OK; } else { result = BUTTON_PRESSED.CANCEL; } - setVisible(false); + setVisible(false); } /** * Returns the tag name entered by the user. - * - * @return a new user tag name + * + * @return a new user tag name */ String getTagName() { return userTagDisplayName; } + String getTagDesciption() { + return userTagDescription; + } + + boolean isTagNotable() { + return userTagIsNotable; + } + /** * Returns information about which button was pressed. - * + * * @return BUTTON_PRESSED (OK, CANCEL) */ BUTTON_PRESSED getResult() { @@ -151,9 +181,9 @@ final class NewTagNameDialog extends javax.swing.JDialog { } /** - * 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. + * 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()); @@ -173,27 +203,40 @@ final class NewTagNameDialog extends javax.swing.JDialog { tagNameTextField = new javax.swing.JTextField(); cancelButton = new javax.swing.JButton(); okButton = new javax.swing.JButton(); + descriptionScrollPane = new javax.swing.JScrollPane(); + descriptionTextArea = new javax.swing.JTextArea(); + descriptionLabel = new javax.swing.JLabel(); + notableCheckbox = new javax.swing.JCheckBox(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.newTagNameLabel.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(newTagNameLabel, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.newTagNameLabel.text")); // NOI18N - tagNameTextField.setText(org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.tagNameTextField.text")); // NOI18N + tagNameTextField.setText(org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.tagNameTextField.text")); // NOI18N - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(NewTagNameDialog.class, "NewTagNameDialog.cancelButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.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(NewTagNameDialog.class, "NewTagNameDialog.okButton.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.okButton.text")); // NOI18N okButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { okButtonActionPerformed(evt); } }); + descriptionTextArea.setColumns(20); + descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + descriptionTextArea.setRows(5); + descriptionScrollPane.setViewportView(descriptionTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.descriptionLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.notableCheckbox.text")); // NOI18N + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -201,13 +244,19 @@ final class NewTagNameDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 220, Short.MAX_VALUE) + .addComponent(tagNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 284, 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)) + .addComponent(newTagNameLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.Alignment.TRAILING) + .addGroup(layout.createSequentialGroup() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(notableCheckbox) + .addComponent(descriptionLabel)) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); layout.setVerticalGroup( @@ -217,13 +266,16 @@ final class NewTagNameDialog extends javax.swing.JDialog { .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) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(descriptionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addComponent(notableCheckbox) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 42, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(cancelButton) - .addComponent(okButton)) - .addContainerGap()) + .addComponent(okButton))) ); pack(); @@ -240,7 +292,11 @@ final class NewTagNameDialog extends javax.swing.JDialog { // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton cancelButton; + private javax.swing.JLabel descriptionLabel; + private javax.swing.JScrollPane descriptionScrollPane; + private javax.swing.JTextArea descriptionTextArea; private javax.swing.JLabel newTagNameLabel; + private javax.swing.JCheckBox notableCheckbox; 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/TagOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form index 3f33f848c0..541bd90cda 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.form @@ -16,7 +16,7 @@ - + @@ -29,7 +29,7 @@ - + @@ -37,43 +37,39 @@ - - - - - - + + + - - - - - + + + - + - - + + - - - + + + + @@ -89,34 +85,46 @@ - + - - + - - - - + + + + + + + + + + + + + + - + - - + + + + - - - + + + - - + + + - + @@ -144,7 +152,7 @@ - + @@ -157,6 +165,15 @@ + + + + + + + + + @@ -170,11 +187,70 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + @@ -187,15 +263,109 @@ - + + + + + + + + + + + + + + + + + + + - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java index c1c9beb5b2..61314e6f1f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java @@ -18,6 +18,9 @@ */ package org.sleuthkit.autopsy.casemodule.services; +import java.awt.EventQueue; +import java.beans.PropertyChangeEvent; +import java.beans.PropertyChangeListener; import java.util.Set; import java.util.TreeSet; import javax.swing.DefaultListModel; @@ -26,7 +29,9 @@ import javax.swing.event.ListSelectionEvent; import org.netbeans.spi.options.OptionsPanelController; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.corecomponents.OptionsPanel; +import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.datamodel.TagName; +import org.sleuthkit.datamodel.TskData; /** * A panel to allow the user to create and delete custom tag types. @@ -36,15 +41,16 @@ 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; + private IngestJobEventPropertyChangeListener ingestJobEventsListener; /** * Creates new form TagsManagerOptionsPanel */ TagOptionsPanel() { tagTypesListModel = new DefaultListModel<>(); - tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions()); + tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions()); initComponents(); customizeComponents(); } @@ -52,8 +58,20 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private void customizeComponents() { tagNamesList.setModel(tagTypesListModel); tagNamesList.addListSelectionListener((ListSelectionEvent event) -> { - enableButtons(); + updatePanel(); }); + addIngestJobEventsListener(); + } + + /** + * Add a property change listener that listens to ingest job events to + * disable the buttons on the panel if ingest is running. This is done to + * prevent changes to user-defined types while the type definitions are in + * use. + */ + private void addIngestJobEventsListener() { + ingestJobEventsListener = new IngestJobEventPropertyChangeListener(); + IngestManager.getInstance().addIngestJobEventListener(ingestJobEventsListener); } /** @@ -66,7 +84,6 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { private void initComponents() { jPanel1 = new javax.swing.JPanel(); - panelDescriptionLabel = new javax.swing.JLabel(); jScrollPane2 = new javax.swing.JScrollPane(); jSplitPane1 = new javax.swing.JSplitPane(); modifyTagTypesListPanel = new javax.swing.JPanel(); @@ -75,14 +92,24 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { tagNamesList = new javax.swing.JList<>(); newTagNameButton = new javax.swing.JButton(); deleteTagNameButton = new javax.swing.JButton(); + editTagNameButton = new javax.swing.JButton(); + jScrollPane3 = new javax.swing.JScrollPane(); + jTextArea1 = new javax.swing.JTextArea(); tagTypesAdditionalPanel = new javax.swing.JPanel(); + descriptionLabel = new javax.swing.JLabel(); + descriptionScrollPane = new javax.swing.JScrollPane(); + descriptionTextArea = new javax.swing.JTextArea(); + isNotableLabel = new javax.swing.JLabel(); + notableYesOrNoLabel = new javax.swing.JLabel(); + ingestRunningWarningLabel = new javax.swing.JLabel(); - jPanel1.setPreferredSize(new java.awt.Dimension(750, 500)); + jPanel1.setPreferredSize(new java.awt.Dimension(750, 490)); - org.openide.awt.Mnemonics.setLocalizedText(panelDescriptionLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionLabel.text")); // NOI18N + jScrollPane2.setPreferredSize(new java.awt.Dimension(750, 490)); - jSplitPane1.setDividerLocation(400); + jSplitPane1.setDividerLocation(365); jSplitPane1.setDividerSize(1); + jSplitPane1.setPreferredSize(new java.awt.Dimension(748, 488)); org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.tagTypesListLabel.text")); // NOI18N @@ -91,6 +118,9 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { 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.setMaximumSize(new java.awt.Dimension(111, 25)); + newTagNameButton.setMinimumSize(new java.awt.Dimension(111, 25)); + newTagNameButton.setPreferredSize(new java.awt.Dimension(111, 25)); newTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { newTagNameButtonActionPerformed(evt); @@ -99,12 +129,37 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { 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.setMaximumSize(new java.awt.Dimension(111, 25)); + deleteTagNameButton.setMinimumSize(new java.awt.Dimension(111, 25)); + deleteTagNameButton.setPreferredSize(new java.awt.Dimension(111, 25)); deleteTagNameButton.addActionListener(new java.awt.event.ActionListener() { public void actionPerformed(java.awt.event.ActionEvent evt) { deleteTagNameButtonActionPerformed(evt); } }); + editTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/edit-tag.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(editTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.editTagNameButton.text")); // NOI18N + editTagNameButton.setMaximumSize(new java.awt.Dimension(111, 25)); + editTagNameButton.setMinimumSize(new java.awt.Dimension(111, 25)); + editTagNameButton.setPreferredSize(new java.awt.Dimension(111, 25)); + editTagNameButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + editTagNameButtonActionPerformed(evt); + } + }); + + jTextArea1.setEditable(false); + jTextArea1.setBackground(new java.awt.Color(240, 240, 240)); + jTextArea1.setColumns(20); + jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + jTextArea1.setLineWrap(true); + jTextArea1.setRows(3); + jTextArea1.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.jTextArea1.text")); // NOI18N + jTextArea1.setWrapStyleWord(true); + jTextArea1.setFocusable(false); + jScrollPane3.setViewportView(jTextArea1); + javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel); modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout); modifyTagTypesListPanelLayout.setHorizontalGroup( @@ -112,40 +167,98 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addContainerGap() .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING) .addComponent(tagTypesListLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() - .addComponent(newTagNameButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(deleteTagNameButton) - .addGap(0, 113, Short.MAX_VALUE))) - .addContainerGap()) - ); - modifyTagTypesListPanelLayout.setVerticalGroup( - modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() - .addContainerGap() - .addComponent(tagTypesListLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 381, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(newTagNameButton) - .addComponent(deleteTagNameButton)) + .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) + .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(javax.swing.GroupLayout.Alignment.LEADING, modifyTagTypesListPanelLayout.createSequentialGroup() + .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))) + .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addGap(0, 0, Short.MAX_VALUE))) .addContainerGap()) ); + modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton}); + + modifyTagTypesListPanelLayout.setVerticalGroup( + modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() + .addGap(10, 10, 10) + .addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(tagTypesListLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 355, Short.MAX_VALUE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(editTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(deleteTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addContainerGap()) + ); + + modifyTagTypesListPanelLayout.linkSize(javax.swing.SwingConstants.VERTICAL, new java.awt.Component[] {deleteTagNameButton, editTagNameButton, newTagNameButton}); + jSplitPane1.setLeftComponent(modifyTagTypesListPanel); + org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.descriptionLabel.text")); // NOI18N + + descriptionTextArea.setEditable(false); + descriptionTextArea.setBackground(new java.awt.Color(240, 240, 240)); + descriptionTextArea.setColumns(20); + descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N + descriptionTextArea.setLineWrap(true); + descriptionTextArea.setRows(5); + descriptionTextArea.setWrapStyleWord(true); + descriptionTextArea.setFocusable(false); + descriptionScrollPane.setViewportView(descriptionTextArea); + + org.openide.awt.Mnemonics.setLocalizedText(isNotableLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.isNotableLabel.text")); // NOI18N + + org.openide.awt.Mnemonics.setLocalizedText(notableYesOrNoLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.notableYesOrNoLabel.text")); // NOI18N + + ingestRunningWarningLabel.setFont(ingestRunningWarningLabel.getFont().deriveFont(ingestRunningWarningLabel.getFont().getStyle() & ~java.awt.Font.BOLD, 11)); + ingestRunningWarningLabel.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/modules/filetypeid/warning16.png"))); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(ingestRunningWarningLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.ingestRunningWarningLabel.text")); // NOI18N + javax.swing.GroupLayout tagTypesAdditionalPanelLayout = new javax.swing.GroupLayout(tagTypesAdditionalPanel); tagTypesAdditionalPanel.setLayout(tagTypesAdditionalPanelLayout); tagTypesAdditionalPanelLayout.setHorizontalGroup( tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 354, Short.MAX_VALUE) + .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup() + .addContainerGap() + .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 361, Short.MAX_VALUE) + .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup() + .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(descriptionLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 92, javax.swing.GroupLayout.PREFERRED_SIZE) + .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup() + .addComponent(isNotableLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 150, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(notableYesOrNoLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE)) + .addComponent(ingestRunningWarningLabel)) + .addGap(0, 0, Short.MAX_VALUE))) + .addContainerGap()) ); tagTypesAdditionalPanelLayout.setVerticalGroup( tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGap(0, 454, Short.MAX_VALUE) + .addGroup(tagTypesAdditionalPanelLayout.createSequentialGroup() + .addContainerGap() + .addComponent(descriptionLabel) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(tagTypesAdditionalPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(isNotableLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(notableYesOrNoLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 304, Short.MAX_VALUE) + .addComponent(ingestRunningWarningLabel) + .addGap(31, 31, 31)) ); jSplitPane1.setRightComponent(tagTypesAdditionalPanel); @@ -157,27 +270,23 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { jPanel1Layout.setHorizontalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(panelDescriptionLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(jScrollPane2)) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); jPanel1Layout.setVerticalGroup( jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createSequentialGroup() - .addContainerGap() - .addComponent(panelDescriptionLabel) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, 458, Short.MAX_VALUE) - .addContainerGap()) + .addGap(0, 0, 0) + .addComponent(jScrollPane2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addGap(0, 0, 0)) ); 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) + .addComponent(jPanel1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) ); layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) @@ -186,11 +295,11 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { }// //GEN-END:initComponents 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(); - TagNameDefiniton newTagType = new TagNameDefiniton(newTagDisplayName, DEFAULT_DESCRIPTION, DEFAULT_COLOR); + TagNameDialog dialog = new TagNameDialog(); + TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); + if (result == TagNameDialog.BUTTON_PRESSED.OK) { + TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; + TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); /* * If tag name already exists, don't add the tag name. */ @@ -198,7 +307,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { tagTypes.add(newTagType); updateTagNamesListModel(); tagNamesList.setSelectedValue(newTagType, true); - enableButtons(); + updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } else { JOptionPane.showMessageDialog(null, @@ -210,23 +319,52 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { }//GEN-LAST:event_newTagNameButtonActionPerformed private void deleteTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteTagNameButtonActionPerformed - TagNameDefiniton tagName = tagNamesList.getSelectedValue(); + TagNameDefinition tagName = tagNamesList.getSelectedValue(); tagTypes.remove(tagName); updateTagNamesListModel(); - enableButtons(); + updatePanel(); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + }//GEN-LAST:event_deleteTagNameButtonActionPerformed + private void editTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_editTagNameButtonActionPerformed + TagNameDefinition originalTagName = tagNamesList.getSelectedValue(); + TagNameDialog dialog = new TagNameDialog(originalTagName); + TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); + if (result == TagNameDialog.BUTTON_PRESSED.OK) { + TskData.FileKnown status = dialog.isTagNotable() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN; + TagNameDefinition newTagType = new TagNameDefinition(dialog.getTagName(), dialog.getTagDesciption(), DEFAULT_COLOR, status); + /* + * If tag name already exists, don't add the tag name. + */ + + tagTypes.remove(originalTagName); + tagTypes.add(newTagType); + updateTagNamesListModel(); + tagNamesList.setSelectedValue(newTagType, true); + updatePanel(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); + } + }//GEN-LAST:event_editTagNameButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton deleteTagNameButton; + private javax.swing.JLabel descriptionLabel; + private javax.swing.JScrollPane descriptionScrollPane; + private javax.swing.JTextArea descriptionTextArea; + private javax.swing.JButton editTagNameButton; + private javax.swing.JLabel ingestRunningWarningLabel; + private javax.swing.JLabel isNotableLabel; private javax.swing.JPanel jPanel1; private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane2; + private javax.swing.JScrollPane jScrollPane3; private javax.swing.JSplitPane jSplitPane1; + private javax.swing.JTextArea jTextArea1; private javax.swing.JPanel modifyTagTypesListPanel; private javax.swing.JButton newTagNameButton; - private javax.swing.JLabel panelDescriptionLabel; - private javax.swing.JList tagNamesList; + private javax.swing.JLabel notableYesOrNoLabel; + private javax.swing.JList tagNamesList; private javax.swing.JPanel tagTypesAdditionalPanel; private javax.swing.JLabel tagTypesListLabel; // End of variables declaration//GEN-END:variables @@ -236,7 +374,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ private void updateTagNamesListModel() { tagTypesListModel.clear(); - for (TagNameDefiniton tagName : tagTypes) { + for (TagNameDefinition tagName : tagTypes) { tagTypesListModel.addElement(tagName); } } @@ -246,9 +384,9 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ @Override public void load() { - tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions()); + tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions()); updateTagNamesListModel(); - enableButtons(); + updatePanel(); } /** @@ -256,19 +394,62 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { */ @Override public void store() { - TagNameDefiniton.setTagNameDefinitions(tagTypes); + TagNameDefinition.setTagNameDefinitions(tagTypes); } /** * Enables the button components based on the state of the tag types list * component. */ - private void enableButtons() { + private void updatePanel() { + boolean ingestIsRunning = IngestManager.getInstance().isIngestRunning(); /* * Only enable the delete button when there is a tag type selected in * the tag types JList. */ - deleteTagNameButton.setEnabled(tagNamesList.getSelectedIndex() != -1); + ingestRunningWarningLabel.setVisible(ingestIsRunning); + boolean isSelected = tagNamesList.getSelectedIndex() != -1; + boolean enableEdit = !ingestIsRunning && isSelected; + editTagNameButton.setEnabled(enableEdit); + boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName()); + deleteTagNameButton.setEnabled(enableDelete); + if (isSelected) { + + descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription()); + if (tagNamesList.getSelectedValue().isNotable()) { + notableYesOrNoLabel.setText("Yes"); + } else { + notableYesOrNoLabel.setText("No"); + } + } else { + descriptionTextArea.setText(""); + notableYesOrNoLabel.setText(""); + } } + /** + * @inheritDoc + */ + @Override + @SuppressWarnings("FinalizeDeclaration") + protected void finalize() throws Throwable { + IngestManager.getInstance().removeIngestJobEventListener(ingestJobEventsListener); + super.finalize(); + } + + /** + * A property change listener that listens to ingest job events. + */ + private class IngestJobEventPropertyChangeListener implements PropertyChangeListener { + + @Override + public void propertyChange(PropertyChangeEvent evt) { + EventQueue.invokeLater(new Runnable() { + @Override + public void run() { + updatePanel(); + } + }); + } + } } diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java index c592e463cb..de16d9456f 100755 --- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java +++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java @@ -20,14 +20,13 @@ package org.sleuthkit.autopsy.casemodule.services; import java.io.Closeable; import java.io.IOException; -import java.util.Arrays; +import java.util.ArrayList; 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; @@ -37,6 +36,7 @@ import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; +import org.sleuthkit.datamodel.TskData; /** * A per case Autopsy service that manages the addition of content and artifact @@ -45,8 +45,7 @@ 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; /** @@ -83,11 +82,11 @@ public class TagsManager implements Closeable { * querying the case database for tag types. */ public static Set getTagDisplayNames() throws TskCoreException { - Set tagDisplayNames = new HashSet<>(STANDARD_TAG_DISPLAY_NAMES); - Set customNames = TagNameDefiniton.getTagNameDefinitions(); + Set tagDisplayNames = new HashSet<>(); + Set customNames = TagNameDefinition.getTagNameDefinitions(); customNames.forEach((tagType) -> { tagDisplayNames.add(tagType.getDisplayName()); - }); + }); try { TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); for (TagName tagName : tagsManager.getAllTagNames()) { @@ -97,7 +96,17 @@ public class TagsManager implements Closeable { /* * No current case, nothing more to add to the set. */ - } + } + return tagDisplayNames; + } + + public static List getNotableTagDisplayNames() { + List tagDisplayNames = new ArrayList<>(); + for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) { + if (tagDef.isNotable()) { + tagDisplayNames.add(tagDef.getDisplayName()); + } + } return tagDisplayNames; } @@ -161,8 +170,8 @@ public class TagsManager implements Closeable { * map. */ Map tagNames = new HashMap<>(); - Set customTypes = TagNameDefiniton.getTagNameDefinitions(); - for (TagNameDefiniton tagType : customTypes) { + Set customTypes = TagNameDefinition.getTagNameDefinitions(); + for (TagNameDefinition tagType : customTypes) { tagNames.put(tagType.getDisplayName(), null); } for (TagName tagName : caseDb.getAllTagNames()) { @@ -186,7 +195,7 @@ public class TagsManager implements Closeable { * name to the case database. */ public synchronized TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException { - return addTagName(displayName, "", TagName.HTML_COLOR.NONE); + return addTagName(displayName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); } /** @@ -205,7 +214,7 @@ public class TagsManager implements Closeable { * name to the case database. */ public synchronized TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException { - return addTagName(displayName, description, TagName.HTML_COLOR.NONE); + return addTagName(displayName, description, TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN); } /** @@ -224,13 +233,32 @@ public class TagsManager implements Closeable { * name to the case database. */ public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException { + return addTagName(displayName, description, color, TskData.FileKnown.UNKNOWN); + } + + /** + * 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. + * @param color The color to associate with the new tag type. + * @param knownStatus The knownStatus to be used for the tag when + * correlating on the tagged item + * + * @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 already exists. + * @throws TskCoreException If there is an error adding the tag + * name to the case database. + */ + public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException { try { - TagName tagName = caseDb.addTagName(displayName, description, color); - if (!STANDARD_TAG_DISPLAY_NAMES.contains(displayName)) { - Set customTypes = TagNameDefiniton.getTagNameDefinitions(); - customTypes.add(new TagNameDefiniton(displayName, description, color)); - TagNameDefiniton.setTagNameDefinitions(customTypes); - } + TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus); + Set customTypes = TagNameDefinition.getTagNameDefinitions(); + customTypes.add(new TagNameDefinition(displayName, description, color, knownStatus)); + TagNameDefinition.setTagNameDefinitions(customTypes); return tagName; } catch (TskCoreException ex) { List existingTagNames = caseDb.getAllTagNames(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java index 7c7d22066e..f9c2435472 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java @@ -53,7 +53,6 @@ public abstract class AbstractSqlEamDb implements EamDb { private int bulkArtifactsCount; protected int bulkArtifactsThreshold; private final Map> bulkArtifacts; - private final List badTags; /** * Connect to the DB and initialize it. @@ -61,7 +60,6 @@ public abstract class AbstractSqlEamDb implements EamDb { * @throws UnknownHostException, EamDbException */ protected AbstractSqlEamDb() throws EamDbException { - badTags = new ArrayList<>(); bulkArtifactsCount = 0; bulkArtifacts = new HashMap<>(); @@ -76,31 +74,6 @@ public abstract class AbstractSqlEamDb implements EamDb { */ protected abstract Connection connect() throws EamDbException; - /** - * Get the list of tags recognized as "Bad" - * - * @return The list of bad tags - */ - @Override - public List getBadTags() { - synchronized (badTags) { - return new ArrayList<>(badTags); - } - } - - /** - * Set the tags recognized as "Bad" - * - * @param tags The tags to consider bad - */ - @Override - public void setBadTags(List tags) { - synchronized (badTags) { - badTags.clear(); - badTags.addAll(tags); - } - } - /** * Add a new name/value pair in the db_info table. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java index 9f7e31fbc5..b021a1fcfc 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java @@ -95,20 +95,6 @@ public interface EamDb { && EamDbPlatformEnum.getSelectedPlatform() != EamDbPlatformEnum.DISABLED; } - /** - * Get the list of tags recognized as "Bad" - * - * @return The list of bad tags - */ - List getBadTags(); - - /** - * Set the tags recognized as "Bad" - * - * @param tags The tags to consider bad - */ - void setBadTags(List tags); - /** * Add a new name/value pair in the db_info table. * @@ -509,7 +495,7 @@ public interface EamDb { * @throws EamDbException */ void addReferenceInstance(EamGlobalFileInstance eamGlobalFileInstance, CorrelationAttribute.Type correlationType) throws EamDbException; - + /** * Insert the bulk collection of Global File Instances * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java index cecba78f4e..c139554c9c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDb.java @@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.centralrepository.datamodel; import java.sql.Connection; import java.sql.SQLException; import java.sql.Statement; -import java.util.List; import java.util.logging.Level; import org.apache.commons.dbcp2.BasicDataSource; import org.sleuthkit.autopsy.coreutils.Logger; @@ -187,14 +186,4 @@ public class PostgresEamDb extends AbstractSqlEamDb { return CONFLICT_CLAUSE; } - @Override - public List getBadTags() { - return dbSettings.getBadTags(); - } - - @Override - public void setBadTags(List badTags) { - dbSettings.setBadTags(badTags); - } - } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java index 6179a58342..bfb3f04b32 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java @@ -24,8 +24,6 @@ import java.sql.PreparedStatement; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.Properties; import java.util.logging.Level; @@ -47,7 +45,6 @@ public final class PostgresEamDbSettings { private final int DEFAULT_BULK_THRESHHOLD = 1000; private final String DEFAULT_USERNAME = ""; private final String DEFAULT_PASSWORD = ""; - private final String DEFAULT_BAD_TAGS = "Evidence"; // NON-NLS private final String VALIDATION_QUERY = "SELECT version()"; // NON-NLS private final String JDBC_BASE_URI = "jdbc:postgresql://"; // NON-NLS private final String JDBC_DRIVER = "org.postgresql.Driver"; // NON-NLS @@ -59,7 +56,6 @@ public final class PostgresEamDbSettings { private int bulkThreshold; private String userName; private String password; - private List badTags; public PostgresEamDbSettings() { loadSettings(); @@ -120,16 +116,6 @@ public final class PostgresEamDbSettings { password = DEFAULT_PASSWORD; } } - - String badTagsStr = ModuleSettings.getConfigSetting("CentralRepository", "db.badTags"); // NON-NLS - if (badTagsStr == null) { - badTagsStr = DEFAULT_BAD_TAGS; - } - if(badTagsStr.isEmpty()){ - badTags = new ArrayList<>(); - } else { - badTags = new ArrayList<>(Arrays.asList(badTagsStr.split(","))); - } } public void saveSettings() { @@ -143,8 +129,6 @@ public final class PostgresEamDbSettings { } catch (TextConverterException ex) { LOGGER.log(Level.SEVERE, "Failed to convert password from text to hex text.", ex); } - - ModuleSettings.setConfigSetting("CentralRepository", "db.badTags", String.join(",", badTags)); // NON-NLS } /** @@ -633,20 +617,6 @@ public final class PostgresEamDbSettings { this.password = password; } - /** - * @return the badTags - */ - public List getBadTags() { - return badTags; - } - - /** - * @param badTags the badTags to set - */ - public void setBadTags(List badTags) { - this.badTags = badTags; - } - /** * @return the VALIDATION_QUERY */ diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java index 719a58385b..3e79f5abca 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java @@ -200,16 +200,7 @@ public class SqliteEamDb extends AbstractSqlEamDb { return ""; } - @Override - public List getBadTags() { - return dbSettings.getBadTags(); - } - - @Override - public void setBadTags(List badTags) { - dbSettings.setBadTags(badTags); - } - + /** * Add a new name/value pair in the db_info table. * diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java index fa50118924..b4ea1aa8a2 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java @@ -26,8 +26,6 @@ import java.sql.Connection; import java.sql.DriverManager; import java.sql.SQLException; import java.sql.Statement; -import java.util.ArrayList; -import java.util.Arrays; import java.util.List; import java.util.logging.Level; import java.util.regex.Pattern; @@ -44,7 +42,6 @@ public final class SqliteEamDbSettings { private final String DEFAULT_DBNAME = "central_repository.db"; // NON-NLS private final String DEFAULT_DBDIRECTORY = PlatformUtil.getUserDirectory() + File.separator + "central_repository"; // NON-NLS private final int DEFAULT_BULK_THRESHHOLD = 1000; - private final String DEFAULT_BAD_TAGS = "Evidence"; // NON-NLS private final String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS private final String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS private final String VALIDATION_QUERY = "SELECT count(*) from sqlite_master"; // NON-NLS @@ -59,7 +56,6 @@ public final class SqliteEamDbSettings { private String dbName; private String dbDirectory; private int bulkThreshold; - private List badTags; public SqliteEamDbSettings() { loadSettings(); @@ -90,15 +86,7 @@ public final class SqliteEamDbSettings { this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; } - String badTagsStr = ModuleSettings.getConfigSetting("CentralRepository", "db.badTags"); // NON-NLS - if (badTagsStr == null) { - badTagsStr = DEFAULT_BAD_TAGS; - } - if (badTagsStr.isEmpty()) { - badTags = new ArrayList<>(); - } else { - badTags = new ArrayList<>(Arrays.asList(badTagsStr.split(","))); - } + } public void saveSettings() { @@ -107,7 +95,6 @@ public final class SqliteEamDbSettings { ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.dbName", getDbName()); // NON-NLS ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.dbDirectory", getDbDirectory()); // NON-NLS ModuleSettings.setConfigSetting("CentralRepository", "db.sqlite.bulkThreshold", Integer.toString(getBulkThreshold())); // NON-NLS - ModuleSettings.setConfigSetting("CentralRepository", "db.badTags", String.join(",", badTags)); // NON-NLS } /** @@ -502,19 +489,7 @@ public final class SqliteEamDbSettings { } } - /** - * @return the badTags - */ - public List getBadTags() { - return badTags; - } - /** - * @param badTags the badTags to set - */ - public void setBadTags(List badTags) { - this.badTags = badTags; - } /** * @return the dbDirectory diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java index a68b0cba8d..dbe17d6e6d 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java @@ -130,7 +130,7 @@ final class CaseEventListener implements PropertyChangeListener { final ContentTagAddedEvent tagAddedEvent = (ContentTagAddedEvent) event; final ContentTag tagAdded = tagAddedEvent.getAddedTag(); - if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { + if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) { if (tagAdded.getContent() instanceof AbstractFile) { af = (AbstractFile) tagAdded.getContent(); knownStatus = TskData.FileKnown.BAD; @@ -151,7 +151,7 @@ final class CaseEventListener implements PropertyChangeListener { long contentID = tagDeletedEvent.getDeletedTagInfo().getContentID(); String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); - if (!dbManager.getBadTags().contains(tagName)) { + if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) { // If the tag that got removed isn't on the list of central repo tags, do nothing return; } @@ -164,7 +164,7 @@ final class CaseEventListener implements PropertyChangeListener { if (tags.stream() .map(tag -> tag.getName().getDisplayName()) - .filter(dbManager.getBadTags()::contains) + .filter(TagsManager.getNotableTagDisplayNames()::contains) .collect(Collectors.toList()) .isEmpty()) { @@ -227,7 +227,7 @@ final class CaseEventListener implements PropertyChangeListener { final BlackBoardArtifactTagAddedEvent tagAddedEvent = (BlackBoardArtifactTagAddedEvent) event; final BlackboardArtifactTag tagAdded = tagAddedEvent.getAddedTag(); - if (dbManager.getBadTags().contains(tagAdded.getName().getDisplayName())) { + if (TagsManager.getNotableTagDisplayNames().contains(tagAdded.getName().getDisplayName())) { content = tagAdded.getContent(); bbArtifact = tagAdded.getArtifact(); knownStatus = TskData.FileKnown.BAD; @@ -245,7 +245,7 @@ final class CaseEventListener implements PropertyChangeListener { long artifactID = tagDeletedEvent.getDeletedTagInfo().getArtifactID(); String tagName = tagDeletedEvent.getDeletedTagInfo().getName().getDisplayName(); - if (!dbManager.getBadTags().contains(tagName)) { + if (!TagsManager.getNotableTagDisplayNames().contains(tagName)) { // If the tag that got removed isn't on the list of central repo tags, do nothing return; } @@ -259,7 +259,7 @@ final class CaseEventListener implements PropertyChangeListener { if (tags.stream() .map(tag -> tag.getName().getDisplayName()) - .filter(dbManager.getBadTags()::contains) + .filter(TagsManager.getNotableTagDisplayNames()::contains) .collect(Collectors.toList()) .isEmpty()) { @@ -350,37 +350,22 @@ final class CaseEventListener implements PropertyChangeListener { if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { Case curCase = (Case) event.getNewValue(); IngestEventsListener.resetCeModuleInstanceCount(); - try { - // only add default evidence tag if case is open and it doesn't already exist in the tags list. - if (Case.isCaseOpen() - && Case.getCurrentCase().getServices().getTagsManager().getAllTagNames().stream() - .map(tag -> tag.getDisplayName()) - .filter(tagName -> Bundle.caseeventlistener_evidencetag().equals(tagName)) - .collect(Collectors.toList()) - .isEmpty()) { - curCase.getServices().getTagsManager().addTagName(Bundle.caseeventlistener_evidencetag()); - } - } catch (TagsManager.TagNameAlreadyExistsException ex) { - LOGGER.info("Evidence tag already exists"); // NON-NLS - } catch (TskCoreException ex) { - LOGGER.log(Level.SEVERE, "Error adding tag.", ex); // NON-NLS - } - + CorrelationCase curCeCase = new CorrelationCase( - -1, - curCase.getName(), // unique case ID - EamOrganization.getDefault(), - curCase.getDisplayName(), - curCase.getCreatedDate(), - curCase.getNumber(), - curCase.getExaminer(), - curCase.getExaminerEmail(), - curCase.getExaminerPhone(), - curCase.getCaseNotes()); + -1, + curCase.getName(), // unique case ID + EamOrganization.getDefault(), + curCase.getDisplayName(), + curCase.getCreatedDate(), + curCase.getNumber(), + curCase.getExaminer(), + curCase.getExaminerEmail(), + curCase.getExaminerPhone(), + curCase.getCaseNotes()); - if (!EamDb.isEnabled()) { - return; - } + if (!EamDb.isEnabled()) { + return; + } try { // NOTE: Cannot determine if the opened case is a new case or a reopened case, diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java index 02d64904a4..0877bc1685 100644 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/IngestEventsListener.java @@ -130,17 +130,18 @@ public class IngestEventsListener { try { AbstractFile af = bbArtifact.getSleuthkitCase().getAbstractFileById(bbArtifact.getObjectID()); - + Collection attributes = new ArrayList<>(); String MODULE_NAME = Bundle.IngestEventsListener_ingestmodule_name(); BlackboardArtifact tifArtifact = af.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT); BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, Bundle.IngestEventsListener_prevTaggedSet_text()); BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, Bundle.IngestEventsListener_prevCaseComment_text() + caseDisplayNames.stream().distinct().collect(Collectors.joining(",", "", ""))); - tifArtifact.addAttribute(att); - tifArtifact.addAttribute(att2); - tifArtifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); + attributes.add(att); + attributes.add(att2); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, bbArtifact.getArtifactID())); + tifArtifact.addAttributes(attributes); try { // index the artifact for keyword search Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties old mode 100644 new mode 100755 index b9ab823b1d..72ecac2866 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/Bundle.properties @@ -21,9 +21,6 @@ ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number ImportHashDatabaseDialog.tfDatabaseName.tooltip=Name for this database ImportHashDatabaseDialog.tfDatabaseVersion.tooltip.text=Database Version Number -GlobalSettingsPanel.bnManageTags.actionCommand= -GlobalSettingsPanel.bnManageTags.toolTipText= -GlobalSettingsPanel.bnManageTags.text=Manage Tags GlobalSettingsPanel.tbOops.text= GlobalSettingsPanel.lbDatabaseSettings.text=Database Settings GlobalSettingsPanel.bnImportDatabase.label=Import Hash Database diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form index 731c177818..53f65a4e6c 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.form @@ -28,7 +28,6 @@ - @@ -47,14 +46,12 @@ - - - + @@ -174,109 +171,6 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java index 37d18036d8..8b6ce90e96 100755 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/GlobalSettingsPanel.java @@ -96,10 +96,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i lbDbNameValue = new javax.swing.JLabel(); lbDbLocationValue = new javax.swing.JLabel(); cbUseCentralRepo = new javax.swing.JCheckBox(); - pnTagManagement = new javax.swing.JPanel(); - bnManageTags = new javax.swing.JButton(); - manageTagsScrollPane = new javax.swing.JScrollPane(); - manageTagsTextArea = new javax.swing.JTextArea(); tbOops = new javax.swing.JTextField(); pnCorrelationProperties = new javax.swing.JPanel(); bnManageTypes = new javax.swing.JButton(); @@ -176,56 +172,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i } }); - pnTagManagement.setBorder(javax.swing.BorderFactory.createTitledBorder(null, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.pnTagManagement.border.title"), javax.swing.border.TitledBorder.DEFAULT_JUSTIFICATION, javax.swing.border.TitledBorder.DEFAULT_POSITION, new java.awt.Font("Tahoma", 0, 12))); // NOI18N - pnTagManagement.setPreferredSize(new java.awt.Dimension(674, 97)); - - org.openide.awt.Mnemonics.setLocalizedText(bnManageTags, org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnManageTags.text")); // NOI18N - bnManageTags.setToolTipText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnManageTags.toolTipText")); // NOI18N - bnManageTags.setActionCommand(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.bnManageTags.actionCommand")); // NOI18N - bnManageTags.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - bnManageTagsActionPerformed(evt); - } - }); - - manageTagsScrollPane.setBorder(null); - - manageTagsTextArea.setEditable(false); - manageTagsTextArea.setBackground(new java.awt.Color(240, 240, 240)); - manageTagsTextArea.setColumns(20); - manageTagsTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - manageTagsTextArea.setLineWrap(true); - manageTagsTextArea.setRows(2); - manageTagsTextArea.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.manageTagsTextArea.text")); // NOI18N - manageTagsTextArea.setToolTipText(""); - manageTagsTextArea.setWrapStyleWord(true); - manageTagsTextArea.setBorder(null); - manageTagsScrollPane.setViewportView(manageTagsTextArea); - - javax.swing.GroupLayout pnTagManagementLayout = new javax.swing.GroupLayout(pnTagManagement); - pnTagManagement.setLayout(pnTagManagementLayout); - pnTagManagementLayout.setHorizontalGroup( - pnTagManagementLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnTagManagementLayout.createSequentialGroup() - .addContainerGap() - .addGroup(pnTagManagementLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnTagManagementLayout.createSequentialGroup() - .addComponent(bnManageTags) - .addGap(0, 555, Short.MAX_VALUE)) - .addGroup(pnTagManagementLayout.createSequentialGroup() - .addComponent(manageTagsScrollPane) - .addContainerGap()))) - ); - pnTagManagementLayout.setVerticalGroup( - pnTagManagementLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(pnTagManagementLayout.createSequentialGroup() - .addGap(7, 7, 7) - .addComponent(manageTagsScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 31, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(bnManageTags, javax.swing.GroupLayout.PREFERRED_SIZE, 25, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(8, 8, 8)) - ); - tbOops.setEditable(false); tbOops.setFont(tbOops.getFont().deriveFont(tbOops.getFont().getStyle() | java.awt.Font.BOLD, 12)); tbOops.setText(org.openide.util.NbBundle.getMessage(GlobalSettingsPanel.class, "GlobalSettingsPanel.tbOops.text")); // NOI18N @@ -338,7 +284,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addComponent(organizationPanel, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(lbCentralRepository, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) - .addComponent(pnTagManagement, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addComponent(cbUseCentralRepo, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 186, javax.swing.GroupLayout.PREFERRED_SIZE)) .addContainerGap()))) @@ -352,25 +297,15 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(pnDatabaseConfiguration, javax.swing.GroupLayout.PREFERRED_SIZE, 119, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) - .addComponent(pnTagManagement, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) .addComponent(pnCorrelationProperties, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(organizationPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addGap(0, 0, 0) .addComponent(tbOops, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(36, 36, 36)) + .addContainerGap()) ); - - pnTagManagement.getAccessibleContext().setAccessibleName(""); }// //GEN-END:initComponents - private void bnManageTagsActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTagsActionPerformed - store(); - ManageTagsDialog dialog = new ManageTagsDialog(); - firePropertyChange(OptionsPanelController.PROP_VALID, null, null); - }//GEN-LAST:event_bnManageTagsActionPerformed - private void bnManageTypesActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnManageTypesActionPerformed store(); ManageCorrelationPropertiesDialog dialog = new ManageCorrelationPropertiesDialog(); @@ -543,10 +478,7 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private boolean enableButtonSubComponents(Boolean enable) { boolean ingestRunning = IngestManager.getInstance().isIngestRunning(); pnCorrelationProperties.setEnabled(enable && !ingestRunning); - pnTagManagement.setEnabled(enable && !ingestRunning); bnManageTypes.setEnabled(enable && !ingestRunning); - bnManageTags.setEnabled(enable && !ingestRunning); - manageTagsTextArea.setEnabled(enable && !ingestRunning); correlationPropertiesTextArea.setEnabled(enable && !ingestRunning); organizationPanel.setEnabled(enable && !ingestRunning); organizationTextArea.setEnabled(enable && !ingestRunning); @@ -556,7 +488,6 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.JButton bnDbConfigure; - private javax.swing.JButton bnManageTags; private javax.swing.JButton bnManageTypes; private javax.swing.JCheckBox cbUseCentralRepo; private javax.swing.JScrollPane correlationPropertiesScrollPane; @@ -569,14 +500,11 @@ public final class GlobalSettingsPanel extends IngestModuleGlobalSettingsPanel i private javax.swing.JLabel lbDbPlatformTypeLabel; private javax.swing.JLabel lbDbPlatformValue; private javax.swing.JButton manageOrganizationButton; - private javax.swing.JScrollPane manageTagsScrollPane; - private javax.swing.JTextArea manageTagsTextArea; private javax.swing.JPanel organizationPanel; private javax.swing.JScrollPane organizationScrollPane; private javax.swing.JTextArea organizationTextArea; private javax.swing.JPanel pnCorrelationProperties; private javax.swing.JPanel pnDatabaseConfiguration; - private javax.swing.JPanel pnTagManagement; private javax.swing.JTextField tbOops; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form deleted file mode 100755 index f1ad5a38e4..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.form +++ /dev/null @@ -1,147 +0,0 @@ - - -
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
-
-
-
-
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
- diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java deleted file mode 100755 index 1960ee3df4..0000000000 --- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java +++ /dev/null @@ -1,370 +0,0 @@ -/* - * Central Repository - * - * Copyright 2015-2017 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.centralrepository.optionspanel; - -import java.awt.Cursor; -import java.awt.Dimension; -import java.awt.Toolkit; -import java.util.ArrayList; -import java.util.Collections; -import java.util.List; -import java.util.logging.Level; -import java.util.stream.Collectors; -import javax.swing.JFrame; -import javax.swing.table.DefaultTableModel; -import javax.swing.event.TableModelEvent; -import javax.swing.event.TableModelListener; -import javax.swing.JOptionPane; -import org.openide.util.NbBundle.Messages; -import org.openide.windows.WindowManager; -import org.sleuthkit.autopsy.casemodule.Case; -import org.sleuthkit.autopsy.casemodule.services.TagsManager; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; -import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; -import org.sleuthkit.autopsy.centralrepository.datamodel.EamArtifactUtil; -import org.sleuthkit.autopsy.coreutils.Logger; -import org.sleuthkit.datamodel.TskCoreException; -import org.sleuthkit.datamodel.BlackboardArtifactTag; -import org.sleuthkit.datamodel.TagName; -import org.sleuthkit.datamodel.ContentTag; -import org.sleuthkit.datamodel.TskData; - -/** - * Instances of this class allow a user to select an existing hash database and - * add it to the set of hash databases used to classify files as unknown, known, - * or notable. - */ -final class ManageTagsDialog extends javax.swing.JDialog { - - private static final Logger LOGGER = Logger.getLogger(ManageTagsDialog.class.getName()); - - /** - * Displays a dialog that allows a user to select an existing hash database - * and add it to the set of hash databases used to classify files as - * unknown, known, or notable. - */ - @Messages({"ManageTagDialog.title=Manage Tags", - "ManageTagDialog.tagInfo.text=Select the tags that cause files and results to be recorded in the central repository. Additional tags can be created in the Tags options panel."}) - ManageTagsDialog() { - super((JFrame) WindowManager.getDefault().getMainWindow(), - Bundle.ManageTagDialog_title(), - true); // NON-NLS - initComponents(); - customizeComponents(); - setupHelpTextArea(); - display(); - } - - - @Messages({"ManageTagsDialog.init.failedConnection.msg=Cannot connect to central cepository.", - "ManageTagsDialog.init.failedGettingTags.msg=Unable to retrieve list of tags.", - "ManageTagsDialog.tagColumn.header.text=Tags", - "ManageTagsDialog.notableColumn.header.text=Notable"}) - private void setupHelpTextArea() { - helpTextArea.setText(Bundle.ManageTagDialog_tagInfo_text()); - } - - private void customizeComponents() { - lbWarnings.setText(""); - EamDb dbManager; - try { - dbManager = EamDb.getInstance(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failed to connect to central repository database."); - lbWarnings.setText(Bundle.ManageTagsDialog_init_failedConnection_msg()); - return; - } - List badTags = dbManager.getBadTags(); - - List tagNames = new ArrayList<>(badTags); - try { - tagNames.addAll( - TagsManager.getTagDisplayNames() - .stream() - .filter(tagName -> !badTags.contains(tagName)) - .collect(Collectors.toList())); - } catch (TskCoreException ex) { - LOGGER.log(Level.WARNING, "Could not get list of tags in case", ex); - lbWarnings.setText(Bundle.ManageTagsDialog_init_failedGettingTags_msg()); - } - - Collections.sort(tagNames); - - DefaultTableModel model = (DefaultTableModel) tblTagNames.getModel(); - model.setColumnIdentifiers(new String[] {Bundle.ManageTagsDialog_tagColumn_header_text(), Bundle.ManageTagsDialog_notableColumn_header_text()}); - for (String tagName : tagNames) { - boolean enabled = badTags.contains(tagName); - model.addRow(new Object[]{tagName, enabled}); - } - CheckBoxModelListener listener = new CheckBoxModelListener(this); - model.addTableModelListener(listener); - } - - private void display() { - Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); - setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); - 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 - * regenerated by the Form Editor. - */ - @SuppressWarnings({"unchecked", "rawtypes"}) - // //GEN-BEGIN:initComponents - private void initComponents() { - - buttonGroup1 = new javax.swing.ButtonGroup(); - okButton = new javax.swing.JButton(); - cancelButton = new javax.swing.JButton(); - tagScrollArea = new javax.swing.JScrollPane(); - tblTagNames = new javax.swing.JTable(); - lbWarnings = new javax.swing.JLabel(); - helpScrollPane = new javax.swing.JScrollPane(); - helpTextArea = new javax.swing.JTextArea(); - - setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); - - org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(ManageTagsDialog.class, "ManageTagsDialog.okButton.text")); // NOI18N - okButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - okButtonActionPerformed(evt); - } - }); - - org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(ManageTagsDialog.class, "ManageTagsDialog.cancelButton.text")); // NOI18N - cancelButton.addActionListener(new java.awt.event.ActionListener() { - public void actionPerformed(java.awt.event.ActionEvent evt) { - cancelButtonActionPerformed(evt); - } - }); - - tblTagNames.setModel(new javax.swing.table.DefaultTableModel( - new Object [][] { - - }, - new String [] { - "", "" - } - ) { - Class[] types = new Class [] { - java.lang.Object.class, java.lang.Boolean.class - }; - boolean[] canEdit = new boolean [] { - false, true - }; - - public Class getColumnClass(int columnIndex) { - return types [columnIndex]; - } - - public boolean isCellEditable(int rowIndex, int columnIndex) { - return canEdit [columnIndex]; - } - }); - tagScrollArea.setViewportView(tblTagNames); - - helpScrollPane.setBorder(null); - - helpTextArea.setEditable(false); - helpTextArea.setBackground(new java.awt.Color(240, 240, 240)); - helpTextArea.setColumns(20); - helpTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N - helpTextArea.setLineWrap(true); - helpTextArea.setRows(3); - helpTextArea.setWrapStyleWord(true); - helpTextArea.setBorder(null); - helpTextArea.setFocusable(false); - helpScrollPane.setViewportView(helpTextArea); - - 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) - .addGroup(layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(okButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton)) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING) - .addComponent(helpScrollPane, javax.swing.GroupLayout.Alignment.LEADING) - .addComponent(tagScrollArea, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, 328, Short.MAX_VALUE) - .addComponent(lbWarnings, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) - .addGap(2, 2, 2))) - .addContainerGap()) - ); - - layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton}); - - layout.setVerticalGroup( - layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addContainerGap() - .addComponent(helpScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 42, javax.swing.GroupLayout.PREFERRED_SIZE) - .addGap(0, 0, 0) - .addComponent(tagScrollArea, javax.swing.GroupLayout.DEFAULT_SIZE, 341, Short.MAX_VALUE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(lbWarnings, javax.swing.GroupLayout.PREFERRED_SIZE, 18, javax.swing.GroupLayout.PREFERRED_SIZE) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(okButton) - .addComponent(cancelButton)) - .addContainerGap()) - ); - - pack(); - }// //GEN-END:initComponents - - private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed - dispose(); - }//GEN-LAST:event_cancelButtonActionPerformed - - - private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed - if (setBadTags()) { - dispose(); - } - }//GEN-LAST:event_okButtonActionPerformed - - private boolean setBadTags() { - List badTags = new ArrayList<>(); - - DefaultTableModel model = (DefaultTableModel) tblTagNames.getModel(); - for (int i = 0; i < model.getRowCount(); ++i) { - String tagName = (String) model.getValueAt(i, 0); - boolean enabled = (boolean) model.getValueAt(i, 1); - - if (enabled) { - badTags.add(tagName); - } - } - try { - EamDb dbManager = EamDb.getInstance(); - dbManager.setBadTags(badTags); - dbManager.saveSettings(); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failed to connect to central repository database."); // NON-NLS - lbWarnings.setText(Bundle.ManageTagsDialog_init_failedConnection_msg()); - return false; - } - return true; - } - - /** - * If the user sets a tag to "Notable", give them the option to update - * any existing tagged items (in the current case only) in the central repo. - */ - public class CheckBoxModelListener implements TableModelListener { - @Messages({"ManageTagsDialog.updateCurrentCase.msg=Mark as notable any files/results in the current case that have this tag?", - "ManageTagsDialog.updateCurrentCase.title=Update current case?", - "ManageTagsDialog.updateCurrentCase.error=Error updating existing central repository entries"}) - - javax.swing.JDialog dialog; - public CheckBoxModelListener(javax.swing.JDialog dialog){ - this.dialog = dialog; - } - - @Override - public void tableChanged(TableModelEvent e) { - int row = e.getFirstRow(); - int column = e.getColumn(); - if (column == 1) { - DefaultTableModel model = (DefaultTableModel) e.getSource(); - String tagName = (String) model.getValueAt(row, 0); - Boolean checked = (Boolean) model.getValueAt(row, column); - if (checked) { - - // Don't do anything if there's no case open - if(Case.isCaseOpen()){ - int dialogButton = JOptionPane.YES_NO_OPTION; - int dialogResult = JOptionPane.showConfirmDialog ( - null, - Bundle.ManageTagsDialog_updateCurrentCase_msg(), - Bundle.ManageTagsDialog_updateCurrentCase_title(), - dialogButton); - if(dialogResult == JOptionPane.YES_OPTION){ - try{ - dialog.setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - setArtifactsKnownBadByTag(tagName, Case.getCurrentCase()); - } catch (EamDbException ex) { - LOGGER.log(Level.SEVERE, "Failed to apply notable status to artifacts in current case", ex); - JOptionPane.showMessageDialog(null, Bundle.ManageTagsDialog_updateCurrentCase_error()); - } finally { - dialog.setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); - } - } - } - } - } - } - } - - /** - * Set knownBad status for all files/artifacts in the given case that - * are tagged with the given tag name. - * Files/artifacts that are not already in the database will be added. - * @param tagName The name of the tag to search for - * @param curCase The case to search in - */ - public void setArtifactsKnownBadByTag(String tagNameString, Case curCase) throws EamDbException{ - try{ - TagName tagName = curCase.getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagNameString); - - // First find any matching artifacts - List artifactTags = curCase.getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName); - - for(BlackboardArtifactTag bbTag:artifactTags){ - List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true); - for (CorrelationAttribute eamArtifact : convertedArtifacts) { - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact,TskData.FileKnown.BAD); - } - } - - // Now search for files - List fileTags = curCase.getSleuthkitCase().getContentTagsByTagName(tagName); - for(ContentTag contentTag:fileTags){ - final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(), - TskData.FileKnown.BAD, ""); - if(eamArtifact != null){ - EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, TskData.FileKnown.BAD); - } - } - } catch (TskCoreException ex){ - throw new EamDbException("Error updating artifacts", ex); - } - - } - - // Variables declaration - do not modify//GEN-BEGIN:variables - private javax.swing.ButtonGroup buttonGroup1; - private javax.swing.JButton cancelButton; - private javax.swing.JScrollPane helpScrollPane; - private javax.swing.JTextArea helpTextArea; - private javax.swing.JLabel lbWarnings; - private javax.swing.JButton okButton; - private javax.swing.JScrollPane tagScrollArea; - private javax.swing.JTable tblTagNames; - // End of variables declaration//GEN-END:variables -} diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java b/Core/src/org/sleuthkit/autopsy/datamodel/DhsImageCategory.java old mode 100755 new mode 100644 similarity index 85% rename from ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java rename to Core/src/org/sleuthkit/autopsy/datamodel/DhsImageCategory.java index 1b2bd604b0..2357c61599 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/Category.java +++ b/Core/src/org/sleuthkit/autopsy/datamodel/DhsImageCategory.java @@ -16,7 +16,7 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package org.sleuthkit.autopsy.imagegallery.datamodel; +package org.sleuthkit.autopsy.datamodel; import com.google.common.collect.ImmutableList; import java.util.Map; @@ -38,6 +38,7 @@ import javafx.scene.layout.CornerRadii; import javafx.scene.layout.Region; import javafx.scene.paint.Color; import org.openide.util.NbBundle; +import org.sleuthkit.autopsy.datamodel.Bundle; /** * Enum to represent the six categories in the DHS image categorization scheme. @@ -48,7 +49,7 @@ import org.openide.util.NbBundle; "Category.four=CAT-4: Exemplar/Comparison (Internal Use Only)", "Category.five=CAT-5: Non-pertinent", "Category.zero=CAT-0: Uncategorized"}) -public enum Category { +public enum DhsImageCategory { /* * This order of declaration is required so that Enum's compareTo method @@ -65,22 +66,21 @@ public enum Category { private static final BorderWidths BORDER_WIDTHS_2 = new BorderWidths(2); private static final CornerRadii CORNER_RADII_4 = new CornerRadii(4); - public static ImmutableList getNonZeroCategories() { + public static ImmutableList getNonZeroCategories() { return nonZeroCategories; } - private static final ImmutableList nonZeroCategories = - ImmutableList.of(Category.FIVE, Category.FOUR, Category.THREE, Category.TWO, Category.ONE); + private static final ImmutableList nonZeroCategories = + ImmutableList.of(DhsImageCategory.FIVE, DhsImageCategory.FOUR, DhsImageCategory.THREE, DhsImageCategory.TWO, DhsImageCategory.ONE); /** * map from displayName to enum value */ - private static final Map nameMap = - Stream.of(values()).collect(Collectors.toMap( - Category::getDisplayName, + private static final Map nameMap = + Stream.of(values()).collect(Collectors.toMap(DhsImageCategory::getDisplayName, Function.identity())); - public static Category fromDisplayName(String displayName) { + public static DhsImageCategory fromDisplayName(String displayName) { return nameMap.get(displayName); } @@ -99,7 +99,7 @@ public enum Category { private final int id; private Image snapshot; - private Category(Color color, int id, String name) { + private DhsImageCategory(Color color, int id, String name) { this.color = color; this.displayName = name; this.id = id; diff --git a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java index 2e1735f3da..6895615bba 100755 --- a/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java +++ b/Core/src/org/sleuthkit/autopsy/datasourceprocessors/AddRawImageTask.java @@ -126,7 +126,7 @@ final class AddRawImageTask implements Runnable { progressMonitor.setProgressText(Bundle.AddRawImageTask_progress_add_text() + imageFilePath); List imageFilePaths = new ArrayList<>(); SleuthkitCase caseDatabase = Case.getCurrentCase().getSleuthkitCase(); - caseDatabase.acquireExclusiveLock(); + caseDatabase.acquireSingleUserCaseWriteLock(); File imageFile = Paths.get(imageFilePath).toFile(); if (!imageFile.exists()) { @@ -181,7 +181,7 @@ final class AddRawImageTask implements Runnable { logger.log(Level.SEVERE, errorMessage, ex); criticalErrorOccurred = true; } finally { - caseDatabase.releaseExclusiveLock(); + caseDatabase.releaseSingleUserCaseReadLock(); } } diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java index eb1ab33591..4bfbb8b734 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java +++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.modules.filetypeid; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.SortedSet; @@ -360,8 +361,9 @@ public class FileTypeDetector { if (fileType.createInterestingFileHit()) { BlackboardArtifact artifact; artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + Collection attributes = new ArrayList<>(); BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, FileTypeIdModuleFactory.getModuleName(), fileType.getInterestingFilesSetName()); - artifact.addAttribute(setNameAttribute); + attributes.add(setNameAttribute); /* * Use the MIME type as the category attribute, i.e., the @@ -369,8 +371,9 @@ public class FileTypeDetector { * files set. */ BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, FileTypeIdModuleFactory.getModuleName(), fileType.getMimeType()); - artifact.addAttribute(ruleNameAttribute); + attributes.add(ruleNameAttribute); + artifact.addAttributes(attributes); /* * Index the artifact for keyword search. */ diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddContentToHashDbAction.java old mode 100755 new mode 100644 diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java index 40db15718f..8087144d65 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/AddHashValuesToDatabaseDialog.java @@ -51,7 +51,7 @@ public class AddHashValuesToDatabaseDialog extends javax.swing.JDialog { */ AddHashValuesToDatabaseDialog(HashDb hashDb) { super((JFrame) WindowManager.getDefault().getMainWindow(), - NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.JDialog.Title", hashDb.getHashSetName()), + NbBundle.getMessage(AddHashValuesToDatabaseDialog.class, "AddHashValuesToDatabaseDialog.JDialog.Title", hashDb.getDisplayName()), true); this.hashDb = hashDb; initComponents(); diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties index e802f9f9f5..3ec2961927 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties @@ -32,7 +32,6 @@ ModalNoButtons.GO_GET_COFFEE_LABEL.text=Hash databases are currently being index ModalNoButtons.CANCEL_BUTTON.text=Cancel HashDbImportDatabaseDialog.knownRadioButton.text=Known (NSRL or other) HashDbCreateDatabaseDialog.knownRadioButton.text=Known -HashDbCreateDatabaseDialog.jLabel1.text=Database Path: HashDbCreateDatabaseDialog.saveAsButton.text=Save As... HashDbCreateDatabaseDialog.hashSetNameTextField.text= HashDbImportDatabaseDialog.jLabel3.text=Database Path: @@ -231,6 +230,12 @@ HashDbImportDatabaseDialog.lbOrg.text=Source Organization: HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only HashDbImportDatabaseDialog.orgButton.text=Manage Organizations HashDbImportDatabaseDialog.versionTextField.text= -HashDbImportDatabaseDialog.fileTypeRadioButton.text=File Type +HashDbImportDatabaseDialog.fileTypeRadioButton.text=File HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository -HashDbImportDatabaseDialog.jLabel4.text=Type: +HashDbImportDatabaseDialog.jLabel4.text=Location: +HashDbCreateDatabaseDialog.jLabel4.text=Location: +HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File +HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository +HashDbCreateDatabaseDialog.lbOrg.text=Source Organization: +HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations +HashDbCreateDatabaseDialog.databasePathLabel.text=Database Path: diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties index 3a1eac32f4..983b48e2a7 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle_ja.properties @@ -27,7 +27,6 @@ ModalNoButtons.GO_GET_COFFEE_LABEL.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30 ModalNoButtons.CANCEL_BUTTON.text=\u30ad\u30e3\u30f3\u30bb\u30eb HashDbImportDatabaseDialog.knownRadioButton.text=\u65e2\u77e5\uff08NSRL\u307e\u305f\u306f\u305d\u306e\u4ed6\uff09 HashDbCreateDatabaseDialog.knownRadioButton.text=\u65e2\u77e5 -HashDbCreateDatabaseDialog.jLabel1.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a HashDbCreateDatabaseDialog.saveAsButton.text=\u540d\u524d\u3092\u3064\u3051\u3066\u4fdd\u5b58\u2026 HashDbImportDatabaseDialog.jLabel3.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=\u30d2\u30c3\u30c8\u6bce\u306b\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30a4\u30f3\u30dc\u30c3\u30af\u30b9\u306b\u30e1\u30c3\u30bb\u30fc\u30b8\u3092\u9001\u308b @@ -209,3 +208,4 @@ HashLookupSettingsPanel.hashDbNameLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b HashLookupSettingsPanel.nameLabel.text=\u30cf\u30c3\u30b7\u30e5\u30bb\u30c3\u30c8\u540d\uff1a HashLookupSettingsPanel.hashDatabasesLabel.text=\u30cf\u30c3\u30b7\u30e5\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\uff1a HashLookupSettingsPanel.importDatabaseButton.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u3092\u30a4\u30f3\u30dd\u30fc\u30c8 +HashDbCreateDatabaseDialog.databasePathLabel.text=\u30c7\u30fc\u30bf\u30d9\u30fc\u30b9\u30d1\u30b9\uff1a diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/EncaseHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/EncaseHashSetParser.java new file mode 100644 index 0000000000..8ea9bc3c46 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/EncaseHashSetParser.java @@ -0,0 +1,169 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2017 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.modules.hashdatabase; + +import java.io.InputStream; +import java.io.BufferedInputStream; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Arrays; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Parser for Encase format hash sets (*.hash) + */ +class EncaseHashSetParser implements HashSetParser { + + private final byte[] encaseHeader = {(byte) 0x48, (byte) 0x41, (byte) 0x53, (byte) 0x48, (byte) 0x0d, (byte) 0x0a, (byte) 0xff, (byte) 0x00, + (byte) 0x02, (byte) 0x00, (byte) 0x00, (byte) 0x00, (byte) 0x01, (byte) 0x00, (byte) 0x00, (byte) 0x00}; + private final String filename; // Name of the input file (saved for logging) + private InputStream inputStream; // File stream for file being imported + private final long expectedHashCount; // Number of hashes we expect to read from the file + private int totalHashesRead = 0; // Number of hashes that have been read + + /** + * Opens the import file and parses the header. If this is successful, the + * file will be set up to call getNextHash() to read the hash values. + * + * @param filename The Encase hash set + * @throws TskCoreException There was an error opening/reading the file or + * it is not the correct format + */ + EncaseHashSetParser(String filename) throws TskCoreException { + try { + this.filename = filename; + inputStream = new BufferedInputStream(new FileInputStream(filename)); + + // Read in and test the 16 byte header + byte[] header = new byte[16]; + readBuffer(header, 16); + if (!Arrays.equals(header, encaseHeader)) { + close(); + throw new TskCoreException("File " + filename + " does not have an Encase header"); + } + + // Read in the expected number of hashes (little endian) + byte[] sizeBuffer = new byte[4]; + readBuffer(sizeBuffer, 4); + expectedHashCount = ((sizeBuffer[3] & 0xff) << 24) | ((sizeBuffer[2] & 0xff) << 16) + | ((sizeBuffer[1] & 0xff) << 8) | (sizeBuffer[0] & 0xff); + + // Read in a bunch of nulls + byte[] filler = new byte[0x3f4]; + readBuffer(filler, 0x3f4); + + // Read in the hash set name + byte[] nameBuffer = new byte[0x50]; + readBuffer(nameBuffer, 0x50); + + // Read in the hash set type + byte[] typeBuffer = new byte[0x28]; + readBuffer(typeBuffer, 0x28); + + // At this point we're past the header and ready to read in the hashes + } catch (IOException ex) { + close(); + throw new TskCoreException("Error reading " + filename, ex); + } catch (TskCoreException ex) { + close(); + throw ex; + } + } + + /** + * Get the expected number of hashes in the file. This number can be an + * estimate. + * + * @return The expected hash count + */ + @Override + public long getExpectedHashCount() { + return expectedHashCount; + } + + /** + * Check if there are more hashes to read + * + * @return true if we've read all expected hash values, false otherwise + */ + @Override + public boolean doneReading() { + return (totalHashesRead >= expectedHashCount); + } + + /** + * Get the next hash to import + * + * @return The hash as a string, or null if the end of file was reached + * without error + * @throws TskCoreException + */ + @Override + public String getNextHash() throws TskCoreException { + if (inputStream == null) { + throw new TskCoreException("Attempting to read from null inputStream"); + } + + byte[] hashBytes = new byte[16]; + byte[] divider = new byte[2]; + try { + + readBuffer(hashBytes, 16); + readBuffer(divider, 2); + + StringBuilder sb = new StringBuilder(); + for (byte b : hashBytes) { + sb.append(String.format("%02x", b)); + } + + totalHashesRead++; + return sb.toString(); + } catch (IOException ex) { + throw new TskCoreException("Ran out of data while reading Encase hash set " + filename, ex); + } + } + + /** + * Closes the import file + */ + @Override + public final void close() { + if (inputStream != null) { + try { + inputStream.close(); + } catch (IOException ex) { + Logger.getLogger(EncaseHashSetParser.class.getName()).log(Level.SEVERE, "Error closing Encase hash set " + filename, ex); + } finally { + inputStream = null; + } + } + } + + private void readBuffer(byte[] buffer, int length) throws TskCoreException, IOException { + if (inputStream == null) { + throw new TskCoreException("readBuffer called on null inputStream"); + } + if (length != inputStream.read(buffer)) { + close(); + throw new TskCoreException("Ran out of data unexpectedly while parsing Encase file " + filename); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form index 3e40c1861d..368903a9d6 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.form @@ -4,6 +4,8 @@ + + @@ -27,16 +29,10 @@ - + - - - - - - @@ -48,52 +44,92 @@ - - - + + + + + - - - + + + + + + + + + + + + + + + - + + + + + + + + - - + + + + + + + + + - - + + + + + + + - - - - - + + + + + + + + + + + + - + @@ -146,10 +182,10 @@
- + - + @@ -203,5 +239,69 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java old mode 100755 new mode 100644 index d07f5a034c..17a69930a2 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java @@ -23,6 +23,7 @@ import java.awt.Toolkit; import java.io.File; import java.io.IOException; import java.nio.file.Paths; +import java.util.List; import java.util.logging.Level; import javax.swing.JFileChooser; import javax.swing.JFrame; @@ -30,12 +31,19 @@ import javax.swing.JOptionPane; import org.apache.commons.io.FilenameUtils; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; +import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDb.KnownFilesType; import org.sleuthkit.autopsy.modules.hashdatabase.HashDbManager.HashDbManagerException; +import org.sleuthkit.datamodel.TskData; +import org.sleuthkit.datamodel.TskCoreException; /** * Instances of this class allow a user to create a new hash database and add it @@ -49,6 +57,8 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private JFileChooser fileChooser = null; private HashDb newHashDb = null; private final static String LAST_FILE_PATH_KEY = "HashDbCreate_Path"; + private EamOrganization selectedOrg = null; + private List orgs = null; /** * Displays a dialog that allows a user to create a new hash database and @@ -59,6 +69,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { super((JFrame) WindowManager.getDefault().getMainWindow(), NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.createHashDbMsg"), true); initFileChooser(); initComponents(); + enableComponents(); display(); } @@ -112,6 +123,46 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { setLocation((screenDimension.width - getSize().width) / 2, (screenDimension.height - getSize().height) / 2); setVisible(true); } + + private void enableComponents(){ + + if(! EamDb.isEnabled()){ + centralRepoRadioButton.setEnabled(false); + fileTypeRadioButton.setSelected(true); + } else { + populateCombobox(); + } + + boolean isFileType = fileTypeRadioButton.isSelected(); + + // Type type only + databasePathLabel.setEnabled(isFileType); + databasePathTextField.setEnabled(isFileType); + saveAsButton.setEnabled(isFileType); + + // Central repo only + lbOrg.setEnabled(! isFileType); + orgButton.setEnabled(! isFileType); + orgComboBox.setEnabled(! isFileType); + } + + @NbBundle.Messages({"HashDbCreateDatabaseDialog.populateOrgsError.message=Failure loading organizations."}) + private void populateCombobox() { + orgComboBox.removeAllItems(); + try { + EamDb dbManager = EamDb.getInstance(); + orgs = dbManager.getOrganizations(); + orgs.forEach((org) -> { + orgComboBox.addItem(org.getName()); + }); + if (!orgs.isEmpty()) { + selectedOrg = orgs.get(0); + } + } catch (EamDbException ex) { + JOptionPane.showMessageDialog(null, Bundle.HashDbCreateDatabaseDialog_populateOrgsError_message()); + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Failure loading organizations", ex); + } + } /** * This method is called from within the constructor to initialize the form. @@ -123,17 +174,24 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { private void initComponents() { buttonGroup1 = new javax.swing.ButtonGroup(); + storageTypeButtonGroup = new javax.swing.ButtonGroup(); saveAsButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton(); knownRadioButton = new javax.swing.JRadioButton(); knownBadRadioButton = new javax.swing.JRadioButton(); - jLabel1 = new javax.swing.JLabel(); + databasePathLabel = new javax.swing.JLabel(); hashSetNameTextField = new javax.swing.JTextField(); jLabel2 = new javax.swing.JLabel(); sendIngestMessagesCheckbox = new javax.swing.JCheckBox(); jLabel3 = new javax.swing.JLabel(); databasePathTextField = new javax.swing.JTextField(); okButton = new javax.swing.JButton(); + jLabel4 = new javax.swing.JLabel(); + fileTypeRadioButton = new javax.swing.JRadioButton(); + centralRepoRadioButton = new javax.swing.JRadioButton(); + lbOrg = new javax.swing.JLabel(); + orgComboBox = new javax.swing.JComboBox<>(); + orgButton = new javax.swing.JButton(); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE); @@ -168,7 +226,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }); - org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel1.text")); // NOI18N + org.openide.awt.Mnemonics.setLocalizedText(databasePathLabel, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.databasePathLabel.text")); // NOI18N hashSetNameTextField.setText(org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.hashSetNameTextField.text")); // NOI18N @@ -194,6 +252,40 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }); + org.openide.awt.Mnemonics.setLocalizedText(jLabel4, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.jLabel4.text")); // NOI18N + + storageTypeButtonGroup.add(fileTypeRadioButton); + fileTypeRadioButton.setSelected(true); + org.openide.awt.Mnemonics.setLocalizedText(fileTypeRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.fileTypeRadioButton.text")); // NOI18N + fileTypeRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + fileTypeRadioButtonActionPerformed(evt); + } + }); + + storageTypeButtonGroup.add(centralRepoRadioButton); + org.openide.awt.Mnemonics.setLocalizedText(centralRepoRadioButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.centralRepoRadioButton.text")); // NOI18N + centralRepoRadioButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + centralRepoRadioButtonActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(lbOrg, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.lbOrg.text")); // NOI18N + + orgComboBox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + orgComboBoxActionPerformed(evt); + } + }); + + org.openide.awt.Mnemonics.setLocalizedText(orgButton, org.openide.util.NbBundle.getMessage(HashDbCreateDatabaseDialog.class, "HashDbCreateDatabaseDialog.orgButton.text")); // NOI18N + orgButton.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + orgButtonActionPerformed(evt); + } + }); + javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane()); getContentPane().setLayout(layout); layout.setHorizontalGroup( @@ -202,11 +294,6 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addContainerGap() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(sendIngestMessagesCheckbox) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(0, 0, Short.MAX_VALUE) - .addComponent(okButton) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) - .addComponent(cancelButton)) .addComponent(jLabel2) .addGroup(layout.createSequentialGroup() .addGap(20, 20, 20) @@ -216,15 +303,32 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { .addGroup(layout.createSequentialGroup() .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addGroup(layout.createSequentialGroup() - .addComponent(jLabel1) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(databasePathTextField)) + .addComponent(lbOrg) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, 130, javax.swing.GroupLayout.PREFERRED_SIZE) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(orgButton, javax.swing.GroupLayout.DEFAULT_SIZE, 145, Short.MAX_VALUE)) .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() - .addComponent(jLabel3) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 272, javax.swing.GroupLayout.PREFERRED_SIZE))) - .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addComponent(jLabel3) + .addComponent(jLabel4) + .addComponent(databasePathLabel)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false) + .addGroup(layout.createSequentialGroup() + .addComponent(fileTypeRadioButton) + .addGap(22, 22, 22) + .addComponent(centralRepoRadioButton)) + .addComponent(hashSetNameTextField, javax.swing.GroupLayout.DEFAULT_SIZE, 305, Short.MAX_VALUE) + .addComponent(databasePathTextField)))) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(saveAsButton))) + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) + .addComponent(okButton) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addComponent(cancelButton) .addContainerGap()) ); @@ -232,29 +336,43 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { layout.setVerticalGroup( layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) - .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() - .addGap(2, 2, 2) + .addGroup(layout.createSequentialGroup() + .addContainerGap() + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(jLabel4) + .addComponent(fileTypeRadioButton) + .addComponent(centralRepoRadioButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(jLabel3) .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(databasePathLabel) .addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) - .addComponent(saveAsButton) - .addComponent(jLabel1)) - .addGap(7, 7, 7) + .addComponent(saveAsButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(lbOrg) + .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) + .addComponent(orgButton)) + .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(jLabel2) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(knownBadRadioButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) - .addComponent(sendIngestMessagesCheckbox) - .addGap(26, 26, 26) - .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) - .addComponent(cancelButton) - .addComponent(okButton)) - .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) + .addGroup(layout.createSequentialGroup() + .addComponent(sendIngestMessagesCheckbox) + .addGap(0, 27, Short.MAX_VALUE)) + .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() + .addGap(0, 0, Short.MAX_VALUE) + .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) + .addComponent(cancelButton) + .addComponent(okButton)))) + .addContainerGap()) ); pack(); @@ -304,6 +422,11 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { } }//GEN-LAST:event_saveAsButtonActionPerformed + @NbBundle.Messages({"HashDbCreateDatabaseDialog.missingOrg=An organization must be selected", + "HashDbCreateDatabaseDialog.duplicateName=A hashset with this name already exists", + "HashDbCreateDatabaseDialog.databaseLookupError=Error accessing central repository", + "HashDbCreateDatabaseDialog.databaseCreationError=Error creating new hash set" + }) private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed // Note that the error handlers in this method call return without disposing of the // dialog to allow the user to try again, if desired. @@ -318,44 +441,101 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { return; } - if (databasePathTextField.getText().isEmpty()) { - JOptionPane.showMessageDialog(this, + if(fileTypeRadioButton.isSelected()){ + if (databasePathTextField.getText().isEmpty()) { + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.mustEnterHashDbPathMsg"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } else { + if(selectedOrg == null){ + JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.mustEnterHashDbPathMsg"), + "HashDbCreateDatabaseDialog.missingOrg"), NbBundle.getMessage(this.getClass(), "HashDbCreateDatabaseDialog.createHashDbErr"), JOptionPane.ERROR_MESSAGE); - return; + return; + } } KnownFilesType type; + TskData.FileKnown fileKnown; if (knownRadioButton.isSelected()) { type = KnownFilesType.KNOWN; + fileKnown = TskData.FileKnown.KNOWN; } else { type = KnownFilesType.KNOWN_BAD; + fileKnown = TskData.FileKnown.BAD; } String errorMessage = NbBundle .getMessage(this.getClass(), "HashDbCreateDatabaseDialog.errMsg.hashDbCreationErr"); - try { - newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); - } catch (IOException ex) { - Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); - JOptionPane.showMessageDialog(this, - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.cannotCreateFileAtLocMsg"), - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.createHashDbErr"), - JOptionPane.ERROR_MESSAGE); - return; - } catch (HashDbManagerException ex) { - Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); - JOptionPane.showMessageDialog(this, - ex.getMessage(), - NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.createHashDbErr"), - JOptionPane.ERROR_MESSAGE); - return; + + if(fileTypeRadioButton.isSelected()){ + try { + newHashDb = HashDbManager.getInstance().addNewHashDatabaseNoSave(hashSetNameTextField.getText(), fileChooser.getSelectedFile().getCanonicalPath(), true, sendIngestMessagesCheckbox.isSelected(), type); + } catch (IOException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.cannotCreateFileAtLocMsg"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } catch (HashDbManagerException ex) { + Logger.getLogger(HashDbCreateDatabaseDialog.class.getName()).log(Level.WARNING, errorMessage, ex); + JOptionPane.showMessageDialog(this, + ex.getMessage(), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } else { + // Check if a hash set with the same name/version already exists + try{ + if(EamDb.getInstance().referenceSetExists(hashSetNameTextField.getText(), "")){ + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.duplicateName"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + } catch (EamDbException ex){ + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error looking up reference set", ex); + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.databaseLookupError"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } + + try{ + int referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(), + "", fileKnown, false)); + newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(), + "", referenceSetID, + true, sendIngestMessagesCheckbox.isSelected(), type, false); + } catch (EamDbException | TskCoreException ex){ + Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error creating new reference set", ex); + JOptionPane.showMessageDialog(this, + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.databaseCreationError"), + NbBundle.getMessage(this.getClass(), + "HashDbCreateDatabaseDialog.createHashDbErr"), + JOptionPane.ERROR_MESSAGE); + return; + } } dispose(); @@ -365,18 +545,52 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog { // TODO add your handling code here: }//GEN-LAST:event_sendIngestMessagesCheckboxActionPerformed + private void orgButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgButtonActionPerformed + ManageOrganizationsDialog dialog = new ManageOrganizationsDialog(); + // update the combobox options + if (dialog.isChanged()) { + populateCombobox(); + } + }//GEN-LAST:event_orgButtonActionPerformed + + private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed + if (null == orgComboBox.getSelectedItem()) return; + String orgName = this.orgComboBox.getSelectedItem().toString(); + for (EamOrganization org : orgs) { + if (org.getName().equals(orgName)) { + selectedOrg = org; + return; + } + } + }//GEN-LAST:event_orgComboBoxActionPerformed + + private void fileTypeRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_fileTypeRadioButtonActionPerformed + enableComponents(); + }//GEN-LAST:event_fileTypeRadioButtonActionPerformed + + private void centralRepoRadioButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_centralRepoRadioButtonActionPerformed + enableComponents(); + }//GEN-LAST:event_centralRepoRadioButtonActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton cancelButton; + private javax.swing.JRadioButton centralRepoRadioButton; + private javax.swing.JLabel databasePathLabel; private javax.swing.JTextField databasePathTextField; + private javax.swing.JRadioButton fileTypeRadioButton; private javax.swing.JTextField hashSetNameTextField; - private javax.swing.JLabel jLabel1; private javax.swing.JLabel jLabel2; private javax.swing.JLabel jLabel3; + private javax.swing.JLabel jLabel4; private javax.swing.JRadioButton knownBadRadioButton; private javax.swing.JRadioButton knownRadioButton; + private javax.swing.JLabel lbOrg; private javax.swing.JButton okButton; + private javax.swing.JButton orgButton; + private javax.swing.JComboBox orgComboBox; private javax.swing.JButton saveAsButton; private javax.swing.JCheckBox sendIngestMessagesCheckbox; + private javax.swing.ButtonGroup storageTypeButtonGroup; // End of variables declaration//GEN-END:variables } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form index 9a3c6acf89..682ec13c34 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form @@ -304,6 +304,9 @@ + + + diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java index c281e81db9..2937d53983 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java @@ -25,7 +25,6 @@ import java.io.IOException; import java.nio.file.Paths; import java.util.List; import java.util.logging.Level; -import javax.swing.JComboBox; import javax.swing.JFileChooser; import javax.swing.JFrame; import javax.swing.JOptionPane; @@ -89,11 +88,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { fileChooser.setMultiSelectionEnabled(false); } - @NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.idx only)"}) + @NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.idx or .hash only)"}) private void updateFileChooserFilter() { fileChooser.resetChoosableFileFilters(); if(centralRepoRadioButton.isSelected()){ - String[] EXTENSION = new String[]{"idx"}; //NON-NLS + String[] EXTENSION = new String[]{"hash", "Hash", "idx"}; //NON-NLS FileNameExtensionFilter filter = new FileNameExtensionFilter( NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.centralRepoExtFilter.text"), EXTENSION); fileChooser.setFileFilter(filter); @@ -132,8 +131,9 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { boolean isFileType = fileTypeRadioButton.isSelected(); // Central repo only - lbVersion.setEnabled(! isFileType); - versionTextField.setEnabled(! isFileType); + lbVersion.setEnabled((! isFileType) && (readOnlyCheckbox.isSelected())); + versionTextField.setEnabled((! isFileType) && (readOnlyCheckbox.isSelected())); + lbOrg.setEnabled(! isFileType); orgButton.setEnabled(! isFileType); orgComboBox.setEnabled(! isFileType); @@ -270,6 +270,11 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { readOnlyCheckbox.setSelected(true); org.openide.awt.Mnemonics.setLocalizedText(readOnlyCheckbox, org.openide.util.NbBundle.getMessage(HashDbImportDatabaseDialog.class, "HashDbImportDatabaseDialog.readOnlyCheckbox.text")); // NOI18N + readOnlyCheckbox.addActionListener(new java.awt.event.ActionListener() { + public void actionPerformed(java.awt.event.ActionEvent evt) { + readOnlyCheckboxActionPerformed(evt); + } + }); storageTypeButtonGroup.add(fileTypeRadioButton); fileTypeRadioButton.setSelected(true); @@ -442,7 +447,8 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { @NbBundle.Messages({"HashDbImportDatabaseDialog.missingVersion=A version must be entered", "HashDbImportDatabaseDialog.missingOrg=An organization must be selected", "HashDbImportDatabaseDialog.duplicateName=A hashset with this name and version already exists", - "HashDbImportDatabaseDialog.databaseLookupError=Error accessing central repository" + "HashDbImportDatabaseDialog.databaseLookupError=Error accessing central repository", + "HashDbImportDatabaseDialog.mustEnterHashSetNameMsg=A hash set name must be entered." }) private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed // Note that the error handlers in this method call return without disposing of the @@ -451,7 +457,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { if (hashSetNameTextField.getText().isEmpty()) { JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), - "HashDbCreateDatabaseDialog.mustEnterHashSetNameMsg"), + "HashDbImportDatabaseDialog.mustEnterHashSetNameMsg"), NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.importHashDbErr"), JOptionPane.ERROR_MESSAGE); @@ -459,7 +465,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } if(centralRepoRadioButton.isSelected()){ - if(versionTextField.getText().isEmpty()){ + if(readOnlyCheckbox.isSelected() && versionTextField.getText().isEmpty()){ JOptionPane.showMessageDialog(this, NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.missingVersion"), @@ -547,10 +553,17 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { return; } + String version; + if(readOnlyCheckbox.isSelected()){ + version = versionTextField.getText(); + } else { + // Editable databases don't have a version + version = ""; + } ImportCentralRepoDbProgressDialog progressDialog = new ImportCentralRepoDbProgressDialog(); - progressDialog.importFile(hashSetNameTextField.getText(), versionTextField.getText(), + progressDialog.importFile(hashSetNameTextField.getText(), version, selectedOrg.getOrgID(), true, sendIngestMessagesCheckbox.isSelected(), type, - this.readOnlyCheckbox.isSelected(), selectedFilePath); + readOnlyCheckbox.isSelected(), selectedFilePath); selectedHashDb = progressDialog.getDatabase(); } @@ -578,9 +591,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { }//GEN-LAST:event_orgButtonActionPerformed private void orgComboBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_orgComboBoxActionPerformed - //JComboBox cb = (JComboBox)evt.getSource(); - //String orgName = (String)cb.getSelectedItem(); - if (null == orgComboBox.getSelectedItem()) return; String orgName = this.orgComboBox.getSelectedItem().toString(); for (EamOrganization org : orgs) { @@ -591,6 +601,10 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog { } }//GEN-LAST:event_orgComboBoxActionPerformed + private void readOnlyCheckboxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_readOnlyCheckboxActionPerformed + enableComponents(); + }//GEN-LAST:event_readOnlyCheckboxActionPerformed + // Variables declaration - do not modify//GEN-BEGIN:variables private javax.swing.ButtonGroup buttonGroup1; private javax.swing.JButton cancelButton; diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java old mode 100755 new mode 100644 index 40cd2230b3..f022f6b657 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java @@ -20,6 +20,7 @@ package org.sleuthkit.autopsy.modules.hashdatabase; import java.io.IOException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.HashMap; import java.util.List; @@ -135,7 +136,7 @@ public class HashDbIngestModule implements FileIngestModule { enabledHashSets.add(db); } } catch (TskCoreException ex) { - logger.log(Level.WARNING, "Error getting index status for " + db.getHashSetName() + " hash database", ex); //NON-NLS + logger.log(Level.WARNING, "Error getting index status for " + db.getDisplayName()+ " hash database", ex); //NON-NLS } } } @@ -218,7 +219,7 @@ public class HashDbIngestModule implements FileIngestModule { name))); ret = ProcessResult.ERROR; } - String hashSetName = db.getHashSetName(); + String hashSetName = db.getDisplayName(); String comment = ""; ArrayList comments = hashInfo.getComments(); @@ -296,14 +297,14 @@ public class HashDbIngestModule implements FileIngestModule { String MODULE_NAME = NbBundle.getMessage(HashDbIngestModule.class, "HashDbIngestModule.moduleName"); BlackboardArtifact badFile = abstractFile.newArtifact(ARTIFACT_TYPE.TSK_HASHSET_HIT); + Collection attributes = new ArrayList<>(); //TODO Revisit usage of deprecated constructor as per TSK-583 //BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID(), MODULE_NAME, "Known Bad", hashSetName); - BlackboardAttribute att2 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, hashSetName); - badFile.addAttribute(att2); - BlackboardAttribute att3 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, MODULE_NAME, md5Hash); - badFile.addAttribute(att3); - BlackboardAttribute att4 = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, comment); - badFile.addAttribute(att4); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, hashSetName)); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_HASH_MD5, MODULE_NAME, md5Hash)); + attributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, comment)); + + badFile.addAttributes(attributes); try { // index the artifact for keyword search diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java old mode 100755 new mode 100644 index e8de1893ca..8e0f5422a1 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java @@ -38,8 +38,10 @@ import org.apache.commons.io.FilenameUtils; import org.netbeans.api.progress.ProgressHandle; import org.openide.util.NbBundle; import org.openide.util.NbBundle.Messages; +import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; +import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalFileInstance; import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.core.RuntimeProperties; import org.sleuthkit.autopsy.coreutils.Logger; @@ -1135,8 +1137,12 @@ public class HashDbManager implements PropertyChangeListener { } @Override - String getDisplayName(){ - return getHashSetName() + " " + getVersion(); + public String getDisplayName(){ + if(! getVersion().isEmpty()){ + return getHashSetName() + " " + getVersion() + " (remote)"; + } else { + return getHashSetName() + " (remote)"; + } } String getVersion(){ @@ -1201,9 +1207,7 @@ public class HashDbManager implements PropertyChangeListener { */ @Override public boolean isUpdateable() throws TskCoreException { - return false; - // TEMP this will change as soon as adding to the database is supported - // return (! readOnly); + return (! readOnly); } /** @@ -1231,7 +1235,26 @@ public class HashDbManager implements PropertyChangeListener { */ @Override public void addHashes(Content content, String comment) throws TskCoreException { - + // This only works for AbstractFiles and MD5 hashes at present. + assert content instanceof AbstractFile; + if (content instanceof AbstractFile) { + AbstractFile file = (AbstractFile) content; + if (null != file.getMd5Hash()) { + TskData.FileKnown type; + if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){ + type = TskData.FileKnown.BAD; + } else { + type = TskData.FileKnown.KNOWN; + } + EamGlobalFileInstance fileInstance = new EamGlobalFileInstance(referenceSetID, file.getMd5Hash(), + type, comment); + try{ + EamDb.getInstance().addReferenceInstance(fileInstance,EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); + } catch (EamDbException ex){ + throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); + } + } + } } /** @@ -1243,7 +1266,23 @@ public class HashDbManager implements PropertyChangeListener { */ @Override public void addHashes(List hashes) throws TskCoreException { + Set globalFileInstances = new HashSet<>(); + for(HashEntry hashEntry:hashes){ + TskData.FileKnown type; + if(knownFilesType.equals(HashDb.KnownFilesType.KNOWN_BAD)){ + type = TskData.FileKnown.BAD; + } else { + type = TskData.FileKnown.KNOWN; + } + globalFileInstances.add(new EamGlobalFileInstance(referenceSetID, hashEntry.getMd5Hash(), type, hashEntry.getComment())); + } + try{ + EamDb.getInstance().bulkInsertReferenceTypeEntries(globalFileInstances, + EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID)); + } catch (EamDbException ex){ + throw new TskCoreException("Error adding hashes to " + getDisplayName(), ex); + } } /** @@ -1331,7 +1370,7 @@ public class HashDbManager implements PropertyChangeListener { @Override public String toString(){ - return getHashSetName(); + return getDisplayName(); } diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java old mode 100755 new mode 100644 index bbe2a4e7d9..63d7a25bfc --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettingsPanel.java @@ -53,8 +53,8 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void initializeHashSetModels(HashLookupModuleSettings settings) { - initializeHashSetModels(settings, hashDbManager.getKnownFileHashSets(), knownHashSetModels); - initializeHashSetModels(settings, hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + initializeHashSetModels(settings, validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); } private void initializeHashSetModels(HashLookupModuleSettings settings, List hashDbs, List hashSetModels) { @@ -125,8 +125,22 @@ public final class HashLookupModuleSettingsPanel extends IngestModuleIngestJobSe } private void updateHashSetModels() { - updateHashSetModels(hashDbManager.getKnownFileHashSets(), knownHashSetModels); - updateHashSetModels(hashDbManager.getKnownBadFileHashSets(), knownBadHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownFileHashSets()), knownHashSetModels); + updateHashSetModels(validSetsOnly(hashDbManager.getKnownBadFileHashSets()), knownBadHashSetModels); + } + + private List validSetsOnly(List hashDbs){ + List validDbs = new ArrayList<>(); + for(HashDb db:hashDbs){ + try{ + if(db.isValid()){ + validDbs.add(db); + } + } catch (TskCoreException ex){ + Logger.getLogger(HashLookupModuleSettingsPanel.class.getName()).log(Level.SEVERE, "Error checking validity for hash set (name = " + db.getHashSetName() + ")", ex); //NON-NLS + } + } + return validDbs; } void updateHashSetModels(List hashDbs, List hashSetModels) { diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java index f24b1ba498..17c629c50a 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java @@ -127,7 +127,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan hashDbOrgLabel.setText(NO_SELECTION_TEXT); hashDbReadOnlyLabel.setText(NO_SELECTION_TEXT); indexPathLabel.setText(NO_SELECTION_TEXT); - // Update indexing components. hashDbIndexStatusLabel.setText(NO_SELECTION_TEXT); @@ -162,14 +161,14 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Update descriptive labels. hashDbNameLabel.setText(db.getHashSetName()); - hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); - try{ - if(db.isUpdateable()){ + hashDbTypeLabel.setText(db.getKnownFilesType().getDisplayName()); + try { + if (db.isUpdateable()) { hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_editable()); } else { hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_readOnly()); } - } catch (TskCoreException ex){ + } catch (TskCoreException ex) { hashDbReadOnlyLabel.setText(Bundle.HashLookupSettingsPanel_updateStatusError()); } @@ -180,30 +179,30 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan addHashesToDatabaseButton.setEnabled(false); } - if(db instanceof SleuthkitHashSet){ - SleuthkitHashSet hashDb = (SleuthkitHashSet)db; - + if (db instanceof SleuthkitHashSet) { + SleuthkitHashSet hashDb = (SleuthkitHashSet) db; + // Disable the central repo fields hashDbVersionLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); hashDbOrgLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); - + // Enable the delete button if ingest is not running deleteDatabaseButton.setEnabled(!ingestIsRunning); - + try { hashDbLocationLabel.setText(shortenPath(db.getDatabasePath())); } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting database path of " + db.getHashSetName() + " hash database", ex); //NON-NLS hashDbLocationLabel.setText(ERROR_GETTING_PATH_TEXT); } - + try { indexPathLabel.setText(shortenPath(hashDb.getIndexPath())); } catch (TskCoreException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error getting index path of " + db.getHashSetName() + " hash database", ex); //NON-NLS indexPathLabel.setText(ERROR_GETTING_PATH_TEXT); } - + // Update indexing components. try { if (hashDb.isIndexing()) { @@ -245,15 +244,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan indexButton.setEnabled(false); } } else { - + // Disable the file type fields/buttons indexPathLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); hashDbIndexStatusLabel.setText(Bundle.HashLookupSettingsPanel_notApplicable()); hashDbLocationLabel.setText(Bundle.HashLookupSettingsPanel_centralRepo()); indexButton.setEnabled(false); deleteDatabaseButton.setEnabled(false); - - CentralRepoHashSet crDb = (CentralRepoHashSet)db; + + CentralRepoHashSet crDb = (CentralRepoHashSet) db; hashDbVersionLabel.setText(crDb.getVersion()); hashDbOrgLabel.setText(crDb.getOrgName()); @@ -302,13 +301,17 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan @Override @Messages({"HashLookupSettingsPanel.saveFail.message=Couldn't save hash db settings.", "HashLookupSettingsPanel.saveFail.title=Save Fail"}) - public void saveSettings() { + public void saveSettings() { + + // Clear out the list of unsaved hashes + newReferenceSetIDs.clear(); + //Checking for for any unindexed databases List unindexed = new ArrayList<>(); for (HashDb db : hashSetManager.getAllHashSets()) { - if(db instanceof SleuthkitHashSet){ + if (db instanceof SleuthkitHashSet) { try { - SleuthkitHashSet hashDatabase = (SleuthkitHashSet)db; + SleuthkitHashSet hashDatabase = (SleuthkitHashSet) db; if (!hashDatabase.hasIndex()) { unindexed.add(hashDatabase); } @@ -320,10 +323,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // If there are unindexed databases, give the user the option to index them now. This // needs to be on the EDT, and will save the hash settings after completing - if(! unindexed.isEmpty()){ - SwingUtilities.invokeLater(new Runnable(){ + if (!unindexed.isEmpty()) { + SwingUtilities.invokeLater(new Runnable() { @Override - public void run(){ + public void run() { //If unindexed ones are found, show a popup box that will either index them, or remove them. if (unindexed.size() == 1) { showInvalidIndex(false, unindexed); @@ -362,20 +365,20 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan */ if (IngestManager.getInstance().isIngestRunning() == false) { // Remove any new central repo hash sets from the database - for(int refID:newReferenceSetIDs){ - try{ - if(EamDb.isEnabled()){ + for (int refID : newReferenceSetIDs) { + try { + if (EamDb.isEnabled()) { EamDb.getInstance().deleteReferenceSet(refID); } else { // This is the case where the user imported a database, then switched over to the central // repo panel and disabled it before cancelling. We can't delete the database at this point. Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.WARNING, "Error reverting central repository hash sets"); //NON-NLS } - } catch (EamDbException ex){ + } catch (EamDbException ex) { Logger.getLogger(HashLookupSettingsPanel.class.getName()).log(Level.SEVERE, "Error reverting central repository hash sets", ex); //NON-NLS } } - + HashDbManager.getInstance().loadLastSavedConfiguration(); } } @@ -397,7 +400,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan * unindexed, along with solutions. This method is related to * ModalNoButtons, to be removed at a later date. * - * @param plural Whether or not there are multiple unindexed databases + * @param plural Whether or not there are multiple unindexed databases * @param unindexed The list of unindexed databases. Can be of size 1. */ private void showInvalidIndex(boolean plural, List unindexed) { @@ -470,8 +473,8 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan getSelectionModel().setSelectionInterval(index, index); } } - - public void selectRowByDatabase(HashDb db){ + + public void selectRowByDatabase(HashDb db) { setSelection(hashSetTableModel.getIndexByDatabase(db)); } @@ -506,10 +509,10 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan @Override public Object getValueAt(int rowIndex, int columnIndex) { - return hashSets.get(rowIndex).getHashSetName(); + return hashSets.get(rowIndex).getDisplayName(); } - private boolean isValid(int rowIndex) { + private boolean isValid(int rowIndex) { try { return hashSets.get(rowIndex).isValid(); } catch (TskCoreException ex) { @@ -542,15 +545,15 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan } } - int getIndexByDatabase(HashDb db){ + int getIndexByDatabase(HashDb db) { for (int i = 0; i < hashSets.size(); ++i) { if (hashSets.get(i).equals(db)) { return i; } } - return -1; + return -1; } - + @Deprecated int getIndexByName(String name) { for (int i = 0; i < hashSets.size(); ++i) { @@ -933,6 +936,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void createDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_createDatabaseButtonActionPerformed HashDb hashDb = new HashDbCreateDatabaseDialog().getHashDatabase(); if (null != hashDb) { + if (hashDb instanceof CentralRepoHashSet) { + int newDbIndex = ((CentralRepoHashSet) hashDb).getReferenceSetID(); + newReferenceSetIDs.add(newDbIndex); + } + hashSetTableModel.refreshModel(); ((HashSetTable) hashSetTable).selectRowByDatabase(hashDb); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -954,7 +962,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan // Add a listener for the INDEXING_DONE event. This listener will update // the UI. - SleuthkitHashSet hashDb = (SleuthkitHashSet)hashDatabase; + SleuthkitHashSet hashDb = (SleuthkitHashSet) hashDatabase; hashDb.addPropertyChangeListener(new PropertyChangeListener() { @Override public void propertyChange(PropertyChangeEvent evt) { @@ -982,11 +990,11 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan private void importDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_importDatabaseButtonActionPerformed HashDb hashDb = new HashDbImportDatabaseDialog().getHashDatabase(); if (null != hashDb) { - if(hashDb instanceof CentralRepoHashSet){ - int newReferenceSetID = ((CentralRepoHashSet)hashDb).getReferenceSetID(); + if (hashDb instanceof CentralRepoHashSet) { + int newReferenceSetID = ((CentralRepoHashSet) hashDb).getReferenceSetID(); newReferenceSetIDs.add(newReferenceSetID); } - + hashSetTableModel.refreshModel(); ((HashSetTable) hashSetTable).selectRowByDatabase(hashDb); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); @@ -996,21 +1004,21 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan @Messages({}) private void deleteDatabaseButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_deleteDatabaseButtonActionPerformed if (JOptionPane.showConfirmDialog(null, - NbBundle.getMessage(this.getClass(), - "HashDbConfigPanel.deleteDbActionConfirmMsg"), - NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"), - JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { - HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); - if (hashDb != null) { - try { - hashSetManager.removeHashDatabaseNoSave(hashDb); - } catch (HashDbManager.HashDbManagerException ex) { - JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_removeDatabaseFailure_message(hashDb.getHashSetName())); + NbBundle.getMessage(this.getClass(), + "HashDbConfigPanel.deleteDbActionConfirmMsg"), + NbBundle.getMessage(this.getClass(), "HashDbConfigPanel.deleteDbActionMsg"), + JOptionPane.YES_NO_OPTION, + JOptionPane.WARNING_MESSAGE) == JOptionPane.YES_OPTION) { + HashDb hashDb = ((HashSetTable) hashSetTable).getSelection(); + if (hashDb != null) { + try { + hashSetManager.removeHashDatabaseNoSave(hashDb); + } catch (HashDbManager.HashDbManagerException ex) { + JOptionPane.showMessageDialog(null, Bundle.HashLookupSettingsPanel_removeDatabaseFailure_message(hashDb.getHashSetName())); + } + hashSetTableModel.refreshModel(); + firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); } - hashSetTableModel.refreshModel(); - firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); - } } }//GEN-LAST:event_deleteDatabaseButtonActionPerformed diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java new file mode 100644 index 0000000000..8a7a3ae034 --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashSetParser.java @@ -0,0 +1,53 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2017 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.modules.hashdatabase; + +import org.sleuthkit.datamodel.TskCoreException; + +interface HashSetParser { + + /** + * Get the next hash to import + * + * @return The hash as a string, or null if the end of file was reached + * without error + * @throws TskCoreException + */ + String getNextHash() throws TskCoreException; + + /** + * Check if there are more hashes to read + * + * @return true if we've read all expected hash values, false otherwise + */ + boolean doneReading(); + + /** + * Get the expected number of hashes in the file. This number can be an + * estimate. + * + * @return The expected hash count + */ + long getExpectedHashCount(); + + /** + * Closes the import file + */ + void close(); +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java new file mode 100644 index 0000000000..0c1b694e1b --- /dev/null +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java @@ -0,0 +1,118 @@ +/* + * Autopsy Forensic Browser + * + * Copyright 2011 - 2017 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.modules.hashdatabase; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.util.logging.Level; +import org.sleuthkit.autopsy.coreutils.Logger; +import org.sleuthkit.datamodel.TskCoreException; + +/** + * Parser for idx files (*.idx) + */ +class IdxHashSetParser implements HashSetParser { + + private final String filename; // Name of the input file (saved for logging) + private BufferedReader reader; // Input file + private final long totalHashes; // Estimated number of hashes + private boolean doneReading = false; // Flag for if we've hit the end of the file + + IdxHashSetParser(String filename) throws TskCoreException { + this.filename = filename; + try { + reader = new BufferedReader(new FileReader(filename)); + } catch (FileNotFoundException ex) { + throw new TskCoreException("Error opening file " + filename, ex); + } + + // Estimate the total number of hashes in the file since counting them all can be slow + File importFile = new File(filename); + long fileSize = importFile.length(); + totalHashes = fileSize / 0x33 + 1; // IDX file lines are generally 0x33 bytes long. We add one to prevent this from being zero + } + + /** + * Get the next hash to import + * + * @return The hash as a string, or null if the end of file was reached + * without error + * @throws TskCoreException + */ + @Override + public String getNextHash() throws TskCoreException { + String line; + + try { + while ((line = reader.readLine()) != null) { + + String[] parts = line.split("\\|"); + + // Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash + if (parts.length != 2 || parts[0].length() == 41) { + continue; + } + + return parts[0].toLowerCase(); + } + } catch (IOException ex) { + throw new TskCoreException("Error reading file " + filename, ex); + } + + // We've run out of data + doneReading = true; + return null; + } + + /** + * Check if there are more hashes to read + * + * @return true if we've read all expected hash values, false otherwise + */ + @Override + public boolean doneReading() { + return doneReading; + } + + /** + * Get the expected number of hashes in the file. This number can be an + * estimate. + * + * @return The expected hash count + */ + @Override + public long getExpectedHashCount() { + return totalHashes; + } + + /** + * Closes the import file + */ + @Override + public void close() { + try { + reader.close(); + } catch (IOException ex) { + Logger.getLogger(IdxHashSetParser.class.getName()).log(Level.SEVERE, "Error closing file " + filename, ex); + } + } +} diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java index 880feabcb7..8e799f4164 100644 --- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java +++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/ImportCentralRepoDbProgressDialog.java @@ -18,12 +18,9 @@ */ package org.sleuthkit.autopsy.modules.hashdatabase; -import java.awt.Cursor; +import java.awt.Color; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeEvent; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileReader; import java.util.HashSet; import java.util.Set; import java.util.logging.Level; @@ -31,8 +28,9 @@ import javax.swing.JFrame; import javax.swing.SwingWorker; import javax.swing.WindowConstants; import java.util.concurrent.atomic.AtomicLong; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; import java.util.concurrent.Executors; -import javax.swing.JOptionPane; import org.openide.util.NbBundle; import org.openide.windows.WindowManager; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttribute; @@ -45,95 +43,111 @@ import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskData; /** - * + * Imports a hash set into the central repository and updates a progress dialog */ -class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements PropertyChangeListener{ +class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements PropertyChangeListener { + + private CentralRepoImportWorker worker; // Swing worker that will import the file and send updates to the dialog + + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress",}) + ImportCentralRepoDbProgressDialog() { + super((JFrame) WindowManager.getDefault().getMainWindow(), + Bundle.ImportCentralRepoDbProgressDialog_title_text(), + true); + + initComponents(); + customizeComponents(); + } + + private void customizeComponents() { + // This is preventing the user from closing the dialog using the X + setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); + + bnOk.setEnabled(false); + } - private CentralRepoImportWorker worker; - /** - * + * Import the selected hash set into the central repository. Will bring up a + * progress dialog while the import is in progress. + * * @param hashSetName * @param version * @param orgId * @param searchDuringIngest * @param sendIngestMessages * @param knownFilesType - * @param importFile + * @param readOnly + * @param importFileName */ - @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.title.text=Central Repository Import Progress", - }) - ImportCentralRepoDbProgressDialog() { - super((JFrame) WindowManager.getDefault().getMainWindow(), - Bundle.ImportCentralRepoDbProgressDialog_title_text(), - true); - - initComponents(); - customizeComponents(); - } - - private void customizeComponents(){ - setDefaultCloseOperation(WindowConstants.DO_NOTHING_ON_CLOSE); - bnOk.setEnabled(false); - } - void importFile(String hashSetName, String version, int orgId, boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, - boolean readOnly, String importFileName){ - setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR)); - - File importFile = new File(importFileName); - worker = new ImportIDXWorker(hashSetName, version, orgId, searchDuringIngest, sendIngestMessages, - knownFilesType, readOnly, importFile); + boolean readOnly, String importFileName) { + + worker = new CentralRepoImportWorker(hashSetName, version, orgId, searchDuringIngest, sendIngestMessages, + knownFilesType, readOnly, importFileName); worker.addPropertyChangeListener(this); worker.execute(); - - setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow()); - setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR)); + + setLocationRelativeTo((JFrame) WindowManager.getDefault().getMainWindow()); this.setVisible(true); } - - HashDbManager.HashDb getDatabase(){ - if(worker != null){ + + /** + * Get the HashDb object for the newly imported data. Should be called after + * importFile completes. + * + * @return The new HashDb object or null if the import failed/was canceled + */ + HashDbManager.HashDb getDatabase() { + if (worker != null) { return worker.getDatabase(); } return null; } - - @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.linesProcessed= lines processed"}) + + /** + * Updates the dialog from events from the worker. The two events we handle + * are progress updates and the done event. + * + * @param evt + */ + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.errorParsingFile.message=Error parsing hash set file"}) @Override public void propertyChange(PropertyChangeEvent evt) { - - if("progress".equals(evt.getPropertyName())){ - progressBar.setValue(worker.getProgressPercentage()); + + if ("progress".equals(evt.getPropertyName())) { + // The progress has been updated. Update the progress bar and text + progressBar.setValue(worker.getProgress()); lbProgress.setText(getProgressString()); } else if ("state".equals(evt.getPropertyName()) && (SwingWorker.StateValue.DONE.equals(evt.getNewValue()))) { - // Disable cancel and enable ok + + // The worker is done processing + // Disable cancel button and enable ok bnCancel.setEnabled(false); bnOk.setEnabled(true); - - progressBar.setValue(progressBar.getMaximum()); - lbProgress.setText(getProgressString()); + + if (worker.getImportSuccess()) { + // If the import succeeded, finish the progress bar and display the + // total number of imported hashes + progressBar.setValue(progressBar.getMaximum()); + lbProgress.setText(getProgressString()); + } else { + // If there was an error, reset the progress bar and display an error message + progressBar.setValue(0); + lbProgress.setForeground(Color.red); + lbProgress.setText(Bundle.ImportCentralRepoDbProgressDialog_errorParsingFile_message()); + } } } - - private String getProgressString(){ - return worker.getLinesProcessed() + Bundle.ImportCentralRepoDbProgressDialog_linesProcessed(); + + @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.linesProcessed.message= hashes processed"}) + private String getProgressString() { + return worker.getNumHashesProcessed() + Bundle.ImportCentralRepoDbProgressDialog_linesProcessed_message(); } - - private interface CentralRepoImportWorker{ - - void execute(); - boolean cancel(boolean mayInterruptIfRunning); - void addPropertyChangeListener(PropertyChangeListener dialog); - int getProgressPercentage(); - long getLinesProcessed(); - HashDbManager.HashDb getDatabase(); - } - - class ImportIDXWorker extends SwingWorker implements CentralRepoImportWorker{ - + + private class CentralRepoImportWorker extends SwingWorker { + private final int HASH_IMPORT_THRESHOLD = 10000; private final String hashSetName; private final String version; @@ -142,16 +156,16 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P private final boolean sendIngestMessages; private final HashDbManager.HashDb.KnownFilesType knownFilesType; private final boolean readOnly; - private final File importFile; - private final long totalLines; - private int referenceSetID = -1; + private final String importFileName; private HashDbManager.CentralRepoHashSet newHashDb = null; - private final AtomicLong numLines = new AtomicLong(); - - ImportIDXWorker(String hashSetName, String version, int orgId, - boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, - boolean readOnly, File importFile){ - + private final AtomicInteger referenceSetID = new AtomicInteger(); + private final AtomicLong hashCount = new AtomicLong(); + private final AtomicBoolean importSuccess = new AtomicBoolean(); + + CentralRepoImportWorker(String hashSetName, String version, int orgId, + boolean searchDuringIngest, boolean sendIngestMessages, HashDbManager.HashDb.KnownFilesType knownFilesType, + boolean readOnly, String importFileName) { + this.hashSetName = hashSetName; this.version = version; this.orgId = orgId; @@ -159,146 +173,163 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P this.sendIngestMessages = sendIngestMessages; this.knownFilesType = knownFilesType; this.readOnly = readOnly; - this.importFile = importFile; - this.numLines.set(0); - - this.totalLines = getEstimatedTotalHashes(); + this.importFileName = importFileName; + this.hashCount.set(0); + this.importSuccess.set(false); + this.referenceSetID.set(-1); } - + /** - * Doing an actual count of the number of lines in a large idx file (such - * as the nsrl) is slow, so just get something in the general area for the - * progress bar. - * @return Approximate number of hashes in the file + * Get the newly created database + * + * @return the imported database. May be null if an error occurred or + * the user canceled */ - final long getEstimatedTotalHashes(){ - long fileSize = importFile.length(); - return (fileSize / 0x33 + 1); // IDX file lines are generally 0x33 bytes long, and we don't want this to be zero - } - - @Override - public HashDbManager.HashDb getDatabase(){ + synchronized HashDbManager.CentralRepoHashSet getDatabase() { return newHashDb; } - - @Override - public long getLinesProcessed(){ - return numLines.get(); + + /** + * Get the number of hashes that have been read in so far + * + * @return current hash count + */ + long getNumHashesProcessed() { + return hashCount.get(); } - - @Override - public int getProgressPercentage(){ - return this.getProgress(); + + /** + * Check if the import was successful or if there was an error. + * + * @return true if the import process completed without error, false + * otherwise + */ + boolean getImportSuccess() { + return importSuccess.get(); } - + @Override protected Void doInBackground() throws Exception { - TskData.FileKnown knownStatus; - if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { - knownStatus = TskData.FileKnown.KNOWN; + // Create the hash set parser + HashSetParser hashSetParser; + if (importFileName.toLowerCase().endsWith(".idx")) { + hashSetParser = new IdxHashSetParser(importFileName); } else { - knownStatus = TskData.FileKnown.BAD; + if (importFileName.toLowerCase().endsWith(".hash")) { + hashSetParser = new EncaseHashSetParser(importFileName); + } else { + // We've gotten here with a format that can't be processed + throw new TskCoreException("Hash set to import is an unknown format : " + importFileName); + } } - - // Create an empty hashset in the central repository - referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly)); - EamDb dbManager = EamDb.getInstance(); - CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); // get "FILES" type - BufferedReader reader = new BufferedReader(new FileReader(importFile)); - String line; - Set globalInstances = new HashSet<>(); - - while ((line = reader.readLine()) != null) { - if(isCancelled()){ - return null; + try { + // Conver to the FileKnown enum used by EamGlobalSet + TskData.FileKnown knownStatus; + if (knownFilesType.equals(HashDbManager.HashDb.KnownFilesType.KNOWN)) { + knownStatus = TskData.FileKnown.KNOWN; + } else { + knownStatus = TskData.FileKnown.BAD; } - String[] parts = line.split("\\|"); + // Create an empty hashset in the central repository + EamDb dbManager = EamDb.getInstance(); + referenceSetID.set(dbManager.newReferenceSet(new EamGlobalSet(orgId, hashSetName, version, knownStatus, readOnly))); - // Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash - if (parts.length != 2 || parts[0].length() == 41) { - continue; - } + // Get the "FILES" content type. This is a database lookup so we + // only want to do it once. + CorrelationAttribute.Type contentType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID); - EamGlobalFileInstance eamGlobalFileInstance = new EamGlobalFileInstance( - referenceSetID, - parts[0].toLowerCase(), - knownStatus, - ""); + // Holds the current batch of hashes that need to be written to the central repo + Set globalInstances = new HashSet<>(); - globalInstances.add(eamGlobalFileInstance); - numLines.incrementAndGet(); + while (!hashSetParser.doneReading()) { + if (isCancelled()) { + return null; + } - if(numLines.get() % HASH_IMPORT_THRESHOLD == 0){ - dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); - globalInstances.clear(); + String newHash = hashSetParser.getNextHash(); - int progress = (int)(numLines.get() * 100 / totalLines); - if(progress < 100){ - this.setProgress(progress); - } else { - this.setProgress(99); + if (newHash != null) { + EamGlobalFileInstance eamGlobalFileInstance = new EamGlobalFileInstance( + referenceSetID.get(), + newHash, + knownStatus, + ""); + + globalInstances.add(eamGlobalFileInstance); + + // If we've hit the threshold for writing the hashes, write them + // all to the central repo + if (hashCount.incrementAndGet() % HASH_IMPORT_THRESHOLD == 0) { + dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); + globalInstances.clear(); + + int progress = (int) (hashCount.get() * 100 / hashSetParser.getExpectedHashCount()); + if (progress < 100) { + this.setProgress(progress); + } else { + this.setProgress(99); + } + } } } + + // Add any remaining hashes to the central repo + dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); + this.setProgress(100); + return null; + } finally { + hashSetParser.close(); } - - dbManager.bulkInsertReferenceTypeEntries(globalInstances, contentType); - this.setProgress(100); - - return null; } - - private void deleteIncompleteSet(int idToDelete){ - if(idToDelete >= 0){ - + + private void deleteIncompleteSet() { + if (referenceSetID.get() >= 0) { + // This can be slow on large reference sets Executors.newSingleThreadExecutor().execute(new Runnable() { - @Override + @Override public void run() { - try{ - EamDb.getInstance().deleteReferenceSet(idToDelete); - } catch (EamDbException ex2){ + try { + EamDb.getInstance().deleteReferenceSet(referenceSetID.get()); + } catch (EamDbException ex2) { Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex2); } } }); } } - - @NbBundle.Messages({"ImportCentralRepoDbProgressDialog.addDbError.message=Error adding new hash set"}) + @Override - protected void done() { - if(isCancelled()){ + synchronized protected void done() { + + if (isCancelled()) { // If the user hit cancel, delete this incomplete hash set from the central repo - deleteIncompleteSet(referenceSetID); + deleteIncompleteSet(); return; } - + try { get(); - try{ - newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetName, version, - referenceSetID, + try { + newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetName, version, + referenceSetID.get(), searchDuringIngest, sendIngestMessages, knownFilesType, readOnly); - } catch (TskCoreException ex){ - JOptionPane.showMessageDialog(null, Bundle.ImportCentralRepoDbProgressDialog_addDbError_message()); + importSuccess.set(true); + } catch (TskCoreException ex) { Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error adding imported hash set", ex); } } catch (Exception ex) { // Delete this incomplete hash set from the central repo - if(referenceSetID >= 0){ - try{ - EamDb.getInstance().deleteReferenceSet(referenceSetID); - } catch (EamDbException ex2){ - Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error deleting incomplete hash set from central repository", ex); - } - } + deleteIncompleteSet(); + Logger.getLogger(ImportCentralRepoDbProgressDialog.class.getName()).log(Level.SEVERE, "Error importing hash set", ex); } - } + } + } - + /** * 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/modules/iOS/CallLogAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java index bb2657c8ef..cfc7272315 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/CallLogAnalyzer.java @@ -23,6 +23,8 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; @@ -116,16 +118,18 @@ class CallLogAnalyzer { type = resultSet.getString("type"); //NON-NLS bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set. + Collection attributes = new ArrayList<>(); if (type.equalsIgnoreCase("outgoing")) { //NON-NLS - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number)); } else { /// Covers INCOMING and MISSED - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, number)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, number)); } - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START, moduleName, date)); // RC: Should be long! - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END, moduleName, duration + date)); // RC: Should be long! - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, type)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_START, moduleName, date)); // RC: Should be long! + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME_END, moduleName, duration + date)); // RC: Should be long! + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, type)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name)); + bba.addAttributes(attributes); try { // index the artifact for keyword search blackboard.indexArtifact(bba); diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java index ecfce79ae4..efa4494f26 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/ContactAnalyzer.java @@ -28,6 +28,8 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; @@ -128,6 +130,7 @@ class ContactAnalyzer { BlackboardArtifact bba; bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT); + Collection attributes = new ArrayList<>(); String name; String oldName = ""; String mimetype; // either phone or email @@ -137,16 +140,16 @@ class ContactAnalyzer { data1 = resultSet.getString("data1"); //NON-NLS mimetype = resultSet.getString("mimetype"); //NON-NLS if (name.equals(oldName) == false) { - bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name)); } if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, moduleName, data1)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, moduleName, data1)); } else { - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1)); } oldName = name; + bba.addAttributes(attributes); try { // index the artifact for keyword search blackboard.indexArtifact(bba); diff --git a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java index 7a7e2f0cfa..d1a81663fe 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java +++ b/Core/src/org/sleuthkit/autopsy/modules/iOS/TextMessageAnalyzer.java @@ -23,6 +23,8 @@ import java.sql.DriverManager; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; +import java.util.ArrayList; +import java.util.Collection; import java.util.List; import java.util.logging.Level; import org.openide.util.NbBundle; @@ -116,21 +118,22 @@ class TextMessageAnalyzer { body = resultSet.getString("body"); //NON-NLS bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set. - + Collection attributes = new ArrayList<>(); // @@@ NEed to put into more specific TO or FROM if (type.equals("1")) { - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.incoming"))); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, address)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.incoming"))); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, address)); } else { - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.outgoing"))); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, address)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.outgoing"))); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, address)); } - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, date)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, type)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, moduleName, subject)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, body)); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.smsMessage"))); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, date)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, type)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, moduleName, subject)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, body)); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName, NbBundle.getMessage(this.getClass(), "TextMessageAnalyzer.bbAttribute.smsMessage"))); + bba.addAttributes(attributes); try { // index the artifact for keyword search blackboard.indexArtifact(bba); diff --git a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java index 78a8481f17..88ee3ae1b7 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/modules/interestingitems/FilesIdentifierIngestModule.java @@ -19,6 +19,7 @@ package org.sleuthkit.autopsy.modules.interestingitems; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.List; import java.util.Map; @@ -121,6 +122,7 @@ final class FilesIdentifierIngestModule implements FileIngestModule { // blackboard. String moduleName = InterestingItemsIngestModuleFactory.getModuleName(); BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); + Collection attributes = new ArrayList<>(); // Add a set name attribute to the artifact. This adds a // fair amount of redundant data to the attributes table @@ -128,13 +130,14 @@ final class FilesIdentifierIngestModule implements FileIngestModule { // otherwise would requires reworking the interesting files // set hit artifact. BlackboardAttribute setNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, moduleName, filesSet.getName()); - artifact.addAttribute(setNameAttribute); + attributes.add(setNameAttribute); // Add a category attribute to the artifact to record the // interesting files set membership rule that was satisfied. BlackboardAttribute ruleNameAttribute = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName, ruleSatisfied); - artifact.addAttribute(ruleNameAttribute); + attributes.add(ruleNameAttribute); + artifact.addAttributes(attributes); try { // index the artifact for keyword search blackboard.indexArtifact(artifact); diff --git a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java index 8a8466d89f..afc84d87aa 100755 --- a/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java +++ b/Core/src/org/sleuthkit/autopsy/modules/stix/StixArtifactData.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.modules.stix; +import java.util.ArrayList; +import java.util.Collection; import java.util.logging.Level; import org.openide.util.NbBundle.Messages; import org.sleuthkit.autopsy.casemodule.Case; @@ -70,10 +72,12 @@ class StixArtifactData { } BlackboardArtifact bba = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT); - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, "Stix", setName)); //NON-NLS - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE, "Stix", observableId)); //NON-NLS - bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS + Collection attributes = new ArrayList<>(); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, "Stix", setName)); //NON-NLS + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TITLE, "Stix", observableId)); //NON-NLS + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, "Stix", objType)); //NON-NLS + bba.addAttributes(attributes); try { // index the artifact for keyword search blackboard.indexArtifact(bba); diff --git a/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java b/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java index 5e9a876ab6..a57623f02e 100755 --- a/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java +++ b/Core/src/org/sleuthkit/autopsy/test/InterestingArtifactCreatorIngestModule.java @@ -18,6 +18,8 @@ */ package org.sleuthkit.autopsy.test; +import java.util.ArrayList; +import java.util.Collection; import java.util.logging.Level; import org.openide.util.Exceptions; @@ -77,6 +79,7 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard(); BlackboardArtifact.Type artifactTypeBase = blackboard.getOrAddArtifactType(ARTIFACT_TYPE_NAMES[randomArtIndex], ARTIFACT_DISPLAY_NAMES[randomArtIndex]); BlackboardArtifact artifactBase = file.newArtifact(artifactTypeBase.getTypeID()); + Collection baseAttributes = new ArrayList<>(); String commentTxt; BlackboardAttribute baseAttr; switch (artifactBase.getArtifactTypeID()) { @@ -84,7 +87,7 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt commentTxt = "www.placeholderWebsiteDOTCOM"; baseAttr = new BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_URL, "Fake Web BookMark", "www.thisWebsiteIsStillFake.com"); - artifactBase.addAttribute(baseAttr); + baseAttributes.add(baseAttr); break; case 9: commentTxt = "fakeKeyword"; @@ -94,29 +97,32 @@ final class InterestingArtifactCreatorIngestModule extends FileIngestModuleAdapt BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, "Fake Keyword Search", "Fake"); BlackboardAttribute keyword = new BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD, "Fake Keyword Search", "FakeKeyword"); - artifactBase.addAttribute(baseAttr); - artifactBase.addAttribute(set); - artifactBase.addAttribute(keyword); + baseAttributes.add(baseAttr); + baseAttributes.add(set); + baseAttributes.add(keyword); break; case 25: commentTxt = "fake phone number from"; baseAttr = new BlackboardAttribute( BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, "Fake Call Log Whatever", "555-555-5555"); - artifactBase.addAttribute(baseAttr); + baseAttributes.add(baseAttr); break; default: commentTxt = "DEPENDENT ON ARTIFACT TYPE"; break; } + artifactBase.addAttributes(baseAttributes); BlackboardArtifact artifact = file.newArtifact(artifactType.getTypeID()); + Collection attributes = new ArrayList<>(); BlackboardAttribute att = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, MODULE_NAME, "ArtifactsAndTxt"); BlackboardAttribute att2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT, MODULE_NAME, commentTxt); BlackboardAttribute att3 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, MODULE_NAME, ""); - artifact.addAttribute(att); - artifact.addAttribute(att2); - artifact.addAttribute(att3); - artifact.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactBase.getArtifactID())); + attributes.add(att); + attributes.add(att2); + attributes.add(att3); + attributes.add(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT, MODULE_NAME, artifactBase.getArtifactID())); + artifact.addAttributes(attributes); } catch (TskCoreException ex) { logger.log(Level.SEVERE, String.format("Failed to process file (obj_id = %d)", file.getId()), ex); return ProcessResult.ERROR; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java index 0cbef7e5d1..3f8b3aecd0 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java @@ -40,7 +40,7 @@ import org.controlsfx.control.action.ActionUtils; import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -60,15 +60,15 @@ public class CategorizeAction extends Action { private final ImageGalleryController controller; private final UndoRedoManager undoManager; - private final Category cat; + private final DhsImageCategory cat; private final Set selectedFileIDs; private final Boolean createUndo; - public CategorizeAction(ImageGalleryController controller, Category cat, Set selectedFileIDs) { + public CategorizeAction(ImageGalleryController controller, DhsImageCategory cat, Set selectedFileIDs) { this(controller, cat, selectedFileIDs, true); } - private CategorizeAction(ImageGalleryController controller, Category cat, Set selectedFileIDs, Boolean createUndo) { + private CategorizeAction(ImageGalleryController controller, DhsImageCategory cat, Set selectedFileIDs, Boolean createUndo) { super(cat.getDisplayName()); this.controller = controller; this.undoManager = controller.getUndoManager(); @@ -103,7 +103,7 @@ public class CategorizeAction extends Action { // Each category get an item in the sub-menu. Selecting one of these menu items adds // a tag with the associated category. - for (final Category cat : Category.values()) { + for (final DhsImageCategory cat : DhsImageCategory.values()) { MenuItem categoryItem = ActionUtils.createMenuItem(new CategorizeAction(controller, cat, selected)); getItems().add(categoryItem); } @@ -118,9 +118,9 @@ public class CategorizeAction extends Action { private final Set fileIDs; private final boolean createUndo; - private final Category cat; + private final DhsImageCategory cat; - CategorizeTask(Set fileIDs, @Nonnull Category cat, boolean createUndo) { + CategorizeTask(Set fileIDs, @Nonnull DhsImageCategory cat, boolean createUndo) { super(); this.fileIDs = fileIDs; java.util.Objects.requireNonNull(cat); @@ -132,14 +132,14 @@ public class CategorizeAction extends Action { public void run() { final DrawableTagsManager tagsManager = controller.getTagsManager(); final CategoryManager categoryManager = controller.getCategoryManager(); - Map oldCats = new HashMap<>(); + Map oldCats = new HashMap<>(); TagName tagName = categoryManager.getTagName(cat); - TagName catZeroTagName = categoryManager.getTagName(Category.ZERO); + TagName catZeroTagName = categoryManager.getTagName(DhsImageCategory.ZERO); for (long fileID : fileIDs) { try { DrawableFile file = controller.getFileFromId(fileID); //drawable db access if (createUndo) { - Category oldCat = file.getCategory(); //drawable db access + DhsImageCategory oldCat = file.getCategory(); //drawable db access TagName oldCatTagName = categoryManager.getTagName(oldCat); if (false == tagName.equals(oldCatTagName)) { oldCats.put(fileID, oldCat); @@ -147,7 +147,7 @@ public class CategorizeAction extends Action { } final List fileTags = tagsManager.getContentTags(file); - if (tagName == categoryManager.getTagName(Category.ZERO)) { + if (tagName == categoryManager.getTagName(DhsImageCategory.ZERO)) { // delete all cat tags for cat-0 fileTags.stream() .filter(tag -> CategoryManager.isCategoryTagName(tag.getName())) @@ -189,11 +189,11 @@ public class CategorizeAction extends Action { @Immutable private final class CategorizationChange implements UndoRedoManager.UndoableCommand { - private final Category newCategory; - private final ImmutableMap oldCategories; + private final DhsImageCategory newCategory; + private final ImmutableMap oldCategories; private final ImageGalleryController controller; - CategorizationChange(ImageGalleryController controller, Category newCategory, Map oldCategories) { + CategorizationChange(ImageGalleryController controller, DhsImageCategory newCategory, Map oldCategories) { this.controller = controller; this.newCategory = newCategory; this.oldCategories = ImmutableMap.copyOf(oldCategories); @@ -216,7 +216,7 @@ public class CategorizeAction extends Action { @Override public void undo() { - for (Map.Entry entry : oldCategories.entrySet()) { + for (Map.Entry entry : oldCategories.entrySet()) { new CategorizeAction(controller, entry.getValue(), Collections.singleton(entry.getKey()), false) .handle(null); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeGroupAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeGroupAction.java index cc2ede2ce5..f568fbd105 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeGroupAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeGroupAction.java @@ -38,7 +38,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryPreferences; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.datamodel.TskCoreException; /** @@ -49,7 +49,7 @@ public class CategorizeGroupAction extends CategorizeAction { private final static Logger LOGGER = Logger.getLogger(CategorizeGroupAction.class.getName()); - public CategorizeGroupAction(Category newCat, ImageGalleryController controller) { + public CategorizeGroupAction(DhsImageCategory newCat, ImageGalleryController controller) { super(controller, newCat, null); setEventHandler(actionEvent -> { ObservableList fileIDs = controller.viewState().get().getGroup().getFileIDs(); @@ -58,12 +58,12 @@ public class CategorizeGroupAction extends CategorizeAction { //if they have preveiously disabled the warning, just go ahead and apply categories. addCatToFiles(ImmutableSet.copyOf(fileIDs)); } else { - final Map catCountMap = new HashMap<>(); + final Map catCountMap = new HashMap<>(); for (Long fileID : fileIDs) { try { - Category category = controller.getFileFromId(fileID).getCategory(); - if (false == Category.ZERO.equals(category) && newCat.equals(category) == false) { + DhsImageCategory category = controller.getFileFromId(fileID).getCategory(); + if (false == DhsImageCategory.ZERO.equals(category) && newCat.equals(category) == false) { catCountMap.merge(category, 1L, Long::sum); } } catch (TskCoreException ex) { @@ -86,14 +86,14 @@ public class CategorizeGroupAction extends CategorizeAction { "CategorizeGroupAction.fileCountMessage={0} with {1}", "CategorizeGroupAction.dontShowAgain=Don't show this message again", "CategorizeGroupAction.fileCountHeader=Files in the following categories will have their categories overwritten: "}) - private void showConfirmationDialog(final Map catCountMap, Category newCat, ObservableList fileIDs) { + private void showConfirmationDialog(final Map catCountMap, DhsImageCategory newCat, ObservableList fileIDs) { ButtonType categorizeButtonType = new ButtonType(Bundle.CategorizeGroupAction_OverwriteButton_text(), ButtonBar.ButtonData.APPLY); VBox textFlow = new VBox(); - for (Map.Entry entry : catCountMap.entrySet()) { + for (Map.Entry entry : catCountMap.entrySet()) { if (entry.getKey().equals(newCat) == false) { if (entry.getValue() > 0) { Label label = new Label(Bundle.CategorizeGroupAction_fileCountMessage(entry.getValue(), entry.getKey().getDisplayName()), diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeSelectedFilesAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeSelectedFilesAction.java index ef70b0f1f6..bb8cd9de96 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeSelectedFilesAction.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeSelectedFilesAction.java @@ -19,14 +19,14 @@ package org.sleuthkit.autopsy.imagegallery.actions; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; /** * */ public class CategorizeSelectedFilesAction extends CategorizeAction { - public CategorizeSelectedFilesAction(Category cat, ImageGalleryController controller) { + public CategorizeSelectedFilesAction(DhsImageCategory cat, ImageGalleryController controller) { super(controller, cat, null); setEventHandler(actionEvent -> addCatToFiles(controller.getSelectionModel().getSelected()) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java index f18e96795b..66aa6c578d 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java @@ -35,10 +35,12 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagAddedEvent; import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TskCoreException; + /** * Provides a cached view of the number of files per category, and fires * {@link CategoryChangeEvent}s when files are categorized. @@ -78,13 +80,13 @@ public class CategoryManager { * the count related methods go through this cache, which loads initial * values from the database if needed. */ - private final LoadingCache categoryCounts = + private final LoadingCache categoryCounts = CacheBuilder.newBuilder().build(CacheLoader.from(this::getCategoryCountHelper)); /** * cached TagNames corresponding to Categories, looked up from * autopsyTagManager at initial request or if invalidated by case change. */ - private final LoadingCache catTagNameMap = + private final LoadingCache catTagNameMap = CacheBuilder.newBuilder().build(CacheLoader.from( cat -> getController().getTagsManager().getTagName(cat) )); @@ -117,18 +119,18 @@ public class CategoryManager { } /** - * get the number of file with the given {@link Category} + * get the number of file with the given {@link DhsImageCategory} * * @param cat get the number of files with Category = cat * * @return the number of files with the given Category */ - synchronized public long getCategoryCount(Category cat) { - if (cat == Category.ZERO) { + synchronized public long getCategoryCount(DhsImageCategory cat) { + if (cat == DhsImageCategory.ZERO) { // Keeping track of the uncategorized files is a bit tricky while ingest // is going on, so always use the list of file IDs we already have along with the // other category counts instead of trying to track it separately. - long allOtherCatCount = getCategoryCount(Category.ONE) + getCategoryCount(Category.TWO) + getCategoryCount(Category.THREE) + getCategoryCount(Category.FOUR) + getCategoryCount(Category.FIVE); + long allOtherCatCount = getCategoryCount(DhsImageCategory.ONE) + getCategoryCount(DhsImageCategory.TWO) + getCategoryCount(DhsImageCategory.THREE) + getCategoryCount(DhsImageCategory.FOUR) + getCategoryCount(DhsImageCategory.FIVE); return db.getNumberOfImageFilesInList() - allOtherCatCount; } else { return categoryCounts.getUnchecked(cat).sum(); @@ -137,24 +139,24 @@ public class CategoryManager { /** * increment the cached value for the number of files with the given - * {@link Category} + * {@link DhsImageCategory} * * @param cat the Category to increment */ - synchronized public void incrementCategoryCount(Category cat) { - if (cat != Category.ZERO) { + synchronized public void incrementCategoryCount(DhsImageCategory cat) { + if (cat != DhsImageCategory.ZERO) { categoryCounts.getUnchecked(cat).increment(); } } /** * decrement the cached value for the number of files with the given - * {@link Category} + * {@link DhsImageCategory} * * @param cat the Category to decrement */ - synchronized public void decrementCategoryCount(Category cat) { - if (cat != Category.ZERO) { + synchronized public void decrementCategoryCount(DhsImageCategory cat) { + if (cat != DhsImageCategory.ZERO) { categoryCounts.getUnchecked(cat).decrement(); } } @@ -169,7 +171,7 @@ public class CategoryManager { * @return a LongAdder whose value is set to the number of file with the * given Category */ - synchronized private LongAdder getCategoryCountHelper(Category cat) { + synchronized private LongAdder getCategoryCountHelper(DhsImageCategory cat) { LongAdder longAdder = new LongAdder(); longAdder.decrement(); try { @@ -186,7 +188,7 @@ public class CategoryManager { * * @param fileIDs */ - public void fireChange(Collection fileIDs, Category newCategory) { + public void fireChange(Collection fileIDs, DhsImageCategory newCategory) { categoryEventBus.post(new CategoryChangeEvent(fileIDs, newCategory)); } @@ -229,21 +231,21 @@ public class CategoryManager { * * @return the TagName used for this Category */ - synchronized public TagName getTagName(Category cat) { + synchronized public TagName getTagName(DhsImageCategory cat) { return catTagNameMap.getUnchecked(cat); } - public static Category categoryFromTagName(TagName tagName) { - return Category.fromDisplayName(tagName.getDisplayName()); + public static DhsImageCategory categoryFromTagName(TagName tagName) { + return DhsImageCategory.fromDisplayName(tagName.getDisplayName()); } public static boolean isCategoryTagName(TagName tName) { - return Category.isCategoryName(tName.getDisplayName()); + return DhsImageCategory.isCategoryName(tName.getDisplayName()); } public static boolean isNotCategoryTagName(TagName tName) { - return Category.isNotCategoryName(tName.getDisplayName()); + return DhsImageCategory.isNotCategoryName(tName.getDisplayName()); } @@ -268,8 +270,8 @@ public class CategoryManager { } catch (TskCoreException tskException) { LOGGER.log(Level.SEVERE, "Failed to get content tags for content. Unable to maintain category in a consistent state.", tskException); //NON-NLS } - Category newCat = CategoryManager.categoryFromTagName(addedTag.getName()); - if (newCat != Category.ZERO) { + DhsImageCategory newCat = CategoryManager.categoryFromTagName(addedTag.getName()); + if (newCat != DhsImageCategory.ZERO) { incrementCategoryCount(newCat); } @@ -283,8 +285,8 @@ public class CategoryManager { TagName tagName = deletedTagInfo.getName(); if (isCategoryTagName(tagName)) { - Category deletedCat = CategoryManager.categoryFromTagName(tagName); - if (deletedCat != Category.ZERO) { + DhsImageCategory deletedCat = CategoryManager.categoryFromTagName(tagName); + if (deletedCat != DhsImageCategory.ZERO) { decrementCategoryCount(deletedCat); } fireChange(Collections.singleton(deletedTagInfo.getContentID()), null); @@ -299,15 +301,15 @@ public class CategoryManager { public static class CategoryChangeEvent { private final ImmutableSet fileIDs; - private final Category newCategory; + private final DhsImageCategory newCategory; - public CategoryChangeEvent(Collection fileIDs, Category newCategory) { + public CategoryChangeEvent(Collection fileIDs, DhsImageCategory newCategory) { super(); this.fileIDs = ImmutableSet.copyOf(fileIDs); this.newCategory = newCategory; } - public Category getNewCategory() { + public DhsImageCategory getNewCategory() { return newCategory; } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java index 96e37d0a83..c3b8771b6d 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import java.util.Arrays; import java.util.Collection; import java.util.Collections; @@ -83,14 +84,14 @@ public class DrawableAttribute> { * //TODO: this has lead to awkward hard to maintain code, and little * advantage. move categories into DrawableDB? */ - public final static DrawableAttribute CATEGORY = - new DrawableAttribute(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(), + public final static DrawableAttribute CATEGORY = + new DrawableAttribute(AttributeName.CATEGORY, Bundle.DrawableAttribute_category(), false, "category-icon.png", //NON-NLS f -> Collections.singleton(f.getCategory())) { @Override - public Node getGraphicForValue(Category val) { + public Node getGraphicForValue(DhsImageCategory val) { return val.getGraphic(); } }; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java index 9f8a6c924e..fa008fe3e9 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -230,7 +231,7 @@ public final class DrawableDB { insertHashHitStmt = prepareStatement("INSERT OR IGNORE INTO hash_set_hits (hash_set_id, obj_id) VALUES (?,?)"); //NON-NLS - for (Category cat : Category.values()) { + for (DhsImageCategory cat : DhsImageCategory.values()) { insertGroup(cat.getDisplayName(), DrawableAttribute.CATEGORY); } initializeImageList(); @@ -1015,7 +1016,7 @@ public final class DrawableDB { case MIME_TYPE: return groupManager.getFileIDsWithMimeType((String) groupKey.getValue()); case CATEGORY: - return groupManager.getFileIDsWithCategory((Category) groupKey.getValue()); + return groupManager.getFileIDsWithCategory((DhsImageCategory) groupKey.getValue()); case TAGS: return groupManager.getFileIDsWithTag((TagName) groupKey.getValue()); } @@ -1194,7 +1195,7 @@ public final class DrawableDB { * * @return the number of the with the given category */ - public long getCategoryCount(Category cat) { + public long getCategoryCount(DhsImageCategory cat) { try { TagName tagName = controller.getTagsManager().getTagName(cat); if (nonNull(tagName)) { @@ -1232,7 +1233,7 @@ public final class DrawableDB { DrawableTagsManager tagsManager = controller.getTagsManager(); // get a comma seperated list of TagName ids for non zero categories - String catTagNameIDs = Category.getNonZeroCategories().stream() + String catTagNameIDs = DhsImageCategory.getNonZeroCategories().stream() .map(tagsManager::getTagName) .map(TagName::getId) .map(Object::toString) diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java index 2f86c47ad6..af26dd2e97 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import java.lang.ref.SoftReference; import java.text.MessageFormat; import java.util.ArrayList; @@ -84,7 +85,7 @@ public abstract class DrawableFile { private final SimpleBooleanProperty analyzed; - private final SimpleObjectProperty category = new SimpleObjectProperty<>(null); + private final SimpleObjectProperty category = new SimpleObjectProperty<>(null); private String make; @@ -215,17 +216,17 @@ public abstract class DrawableFile { return ""; } - public void setCategory(Category category) { + public void setCategory(DhsImageCategory category) { categoryProperty().set(category); } - public Category getCategory() { + public DhsImageCategory getCategory() { updateCategory(); return category.get(); } - public SimpleObjectProperty categoryProperty() { + public SimpleObjectProperty categoryProperty() { return category; } @@ -237,9 +238,9 @@ public abstract class DrawableFile { category.set(getContentTags().stream() .map(Tag::getName).filter(CategoryManager::isCategoryTagName) .map(TagName::getDisplayName) - .map(Category::fromDisplayName) + .map(DhsImageCategory::fromDisplayName) .sorted().findFirst() //sort by severity and take the first - .orElse(Category.ZERO) + .orElse(DhsImageCategory.ZERO) ); } catch (TskCoreException ex) { LOGGER.log(Level.WARNING, "problem looking up category for " + this.getContentPathSafe(), ex); //NON-NLS diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java index 2172aacf51..cb30c37bab 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java @@ -18,6 +18,7 @@ */ package org.sleuthkit.autopsy.imagegallery.datamodel; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import com.google.common.eventbus.AsyncEventBus; import com.google.common.eventbus.EventBus; import java.util.Collections; @@ -51,19 +52,9 @@ public class DrawableTagsManager { private static final Logger LOGGER = Logger.getLogger(DrawableTagsManager.class.getName()); - private static final String FOLLOW_UP = Bundle.DrawableTagsManager_followUp(); - private static final String BOOKMARK = Bundle.DrawableTagsManager_bookMark(); private static Image FOLLOW_UP_IMAGE; private static Image BOOKMARK_IMAGE; - public static String getFollowUpText() { - return FOLLOW_UP; - } - - public static String getBookmarkText() { - return BOOKMARK; - } - final private Object autopsyTagsManagerLock = new Object(); private TagsManager autopsyTagsManager; @@ -147,7 +138,7 @@ public class DrawableTagsManager { public TagName getFollowUpTagName() throws TskCoreException { synchronized (autopsyTagsManagerLock) { if (Objects.isNull(followUpTagName)) { - followUpTagName = getTagName(FOLLOW_UP); + followUpTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.followUp")); } return followUpTagName; } @@ -156,12 +147,13 @@ public class DrawableTagsManager { private Object getBookmarkTagName() throws TskCoreException { synchronized (autopsyTagsManagerLock) { if (Objects.isNull(bookmarkTagName)) { - bookmarkTagName = getTagName(BOOKMARK); + bookmarkTagName = getTagName(NbBundle.getMessage(DrawableTagsManager.class, "DrawableTagsManager.bookMark")); } return bookmarkTagName; } } + /** * get all the TagNames that are not categories * @@ -237,7 +229,7 @@ public class DrawableTagsManager { } } - public TagName getTagName(Category cat) { + public TagName getTagName(DhsImageCategory cat) { try { return getTagName(cat.getDisplayName()); } catch (TskCoreException ex) { diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java index 5c02f5abd1..7dddfa5ca8 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/grouping/GroupManager.java @@ -71,7 +71,7 @@ import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableDB; @@ -332,7 +332,7 @@ public class GroupManager { switch (groupBy.attrName) { //these cases get special treatment case CATEGORY: - values = (List) Arrays.asList(Category.values()); + values = (List) Arrays.asList(DhsImageCategory.values()); break; case TAGS: values = (List) controller.getTagsManager().getTagNamesInUse().stream() @@ -388,7 +388,7 @@ public class GroupManager { switch (groupKey.getAttribute().attrName) { //these cases get special treatment case CATEGORY: - fileIDsToReturn = getFileIDsWithCategory((Category) groupKey.getValue()); + fileIDsToReturn = getFileIDsWithCategory((DhsImageCategory) groupKey.getValue()); break; case TAGS: fileIDsToReturn = getFileIDsWithTag((TagName) groupKey.getValue()); @@ -409,13 +409,13 @@ public class GroupManager { // @@@ This was kind of slow in the profiler. Maybe we should cache it. // Unless the list of file IDs is necessary, use countFilesWithCategory() to get the counts. - public Set getFileIDsWithCategory(Category category) throws TskCoreException { + public Set getFileIDsWithCategory(DhsImageCategory category) throws TskCoreException { Set fileIDsToReturn = Collections.emptySet(); if (nonNull(db)) { try { final DrawableTagsManager tagsManager = controller.getTagsManager(); - if (category == Category.ZERO) { - List< TagName> tns = Stream.of(Category.ONE, Category.TWO, Category.THREE, Category.FOUR, Category.FIVE) + if (category == DhsImageCategory.ZERO) { + List< TagName> tns = Stream.of(DhsImageCategory.ONE, DhsImageCategory.TWO, DhsImageCategory.THREE, DhsImageCategory.FOUR, DhsImageCategory.FIVE) .map(tagsManager::getTagName) .collect(Collectors.toList()); diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java index 708568fe41..44814e2c9a 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/SummaryTablePane.java @@ -36,7 +36,7 @@ import org.openide.util.NbBundle; import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; /** * Displays summary statistics (counts) for each group @@ -44,13 +44,13 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.Category; public class SummaryTablePane extends AnchorPane { @FXML - private TableColumn, String> catColumn; + private TableColumn, String> catColumn; @FXML - private TableColumn, Long> countColumn; + private TableColumn, Long> countColumn; @FXML - private TableView> tableView; + private TableView> tableView; private final ImageGalleryController controller; @FXML @@ -67,11 +67,11 @@ public class SummaryTablePane extends AnchorPane { tableView.prefHeightProperty().set(7 * 25); //set up columns - catColumn.setCellValueFactory((TableColumn.CellDataFeatures, String> p) -> new SimpleObjectProperty<>(p.getValue().getKey().getDisplayName())); + catColumn.setCellValueFactory((TableColumn.CellDataFeatures, String> p) -> new SimpleObjectProperty<>(p.getValue().getKey().getDisplayName())); catColumn.setPrefWidth(USE_COMPUTED_SIZE); catColumn.setText(Bundle.SummaryTablePane_catColumn()); - countColumn.setCellValueFactory((TableColumn.CellDataFeatures, Long> p) -> new SimpleObjectProperty<>(p.getValue().getValue())); + countColumn.setCellValueFactory((TableColumn.CellDataFeatures, Long> p) -> new SimpleObjectProperty<>(p.getValue().getValue())); countColumn.setPrefWidth(USE_COMPUTED_SIZE); countColumn.setText(Bundle.SummaryTablePane_countColumn()); @@ -93,9 +93,9 @@ public class SummaryTablePane extends AnchorPane { */ @Subscribe public void handleCategoryChanged(org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager.CategoryChangeEvent evt) { - final ObservableList> data = FXCollections.observableArrayList(); + final ObservableList> data = FXCollections.observableArrayList(); if (Case.isCaseOpen()) { - for (Category cat : Category.values()) { + for (DhsImageCategory cat : DhsImageCategory.values()) { data.add(new Pair<>(cat, controller.getCategoryManager().getCategoryCount(cat))); } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java index bdc43c1c06..40dad21cf2 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/Toolbar.java @@ -49,7 +49,7 @@ import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.actions.CategorizeGroupAction; import org.sleuthkit.autopsy.imagegallery.actions.TagGroupAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupSortBy; @@ -154,13 +154,13 @@ public class Toolbar extends ToolBar { } }); - CategorizeGroupAction cat5GroupAction = new CategorizeGroupAction(Category.FIVE, controller); + CategorizeGroupAction cat5GroupAction = new CategorizeGroupAction(DhsImageCategory.FIVE, controller); catGroupMenuButton.setOnAction(cat5GroupAction); catGroupMenuButton.setText(cat5GroupAction.getText()); catGroupMenuButton.setGraphic(cat5GroupAction.getGraphic()); catGroupMenuButton.showingProperty().addListener(showing -> { if (catGroupMenuButton.isShowing()) { - List categoryMenues = Lists.transform(Arrays.asList(Category.values()), + List categoryMenues = Lists.transform(Arrays.asList(DhsImageCategory.values()), cat -> GuiUtils.createAutoAssigningMenuItem(catGroupMenuButton, new CategorizeGroupAction(cat, controller))); catGroupMenuButton.getItems().setAll(categoryMenues); } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java index 6668657619..afed2fd832 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/DrawableView.java @@ -17,7 +17,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -38,17 +38,17 @@ public interface DrawableView { static final Border HASH_BORDER = new Border(new BorderStroke(Color.PURPLE, BorderStrokeStyle.DASHED, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT1_BORDER = new Border(new BorderStroke(Category.ONE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT1_BORDER = new Border(new BorderStroke(DhsImageCategory.ONE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT2_BORDER = new Border(new BorderStroke(Category.TWO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT2_BORDER = new Border(new BorderStroke(DhsImageCategory.TWO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT3_BORDER = new Border(new BorderStroke(Category.THREE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT3_BORDER = new Border(new BorderStroke(DhsImageCategory.THREE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT4_BORDER = new Border(new BorderStroke(Category.FOUR.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT4_BORDER = new Border(new BorderStroke(DhsImageCategory.FOUR.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT5_BORDER = new Border(new BorderStroke(Category.FIVE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT5_BORDER = new Border(new BorderStroke(DhsImageCategory.FIVE.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); - static final Border CAT0_BORDER = new Border(new BorderStroke(Category.ZERO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); + static final Border CAT0_BORDER = new Border(new BorderStroke(DhsImageCategory.ZERO.getColor(), BorderStrokeStyle.SOLID, CAT_CORNER_RADII, CAT_BORDER_WIDTHS)); Region getCategoryBorderRegion(); @@ -97,7 +97,7 @@ public interface DrawableView { } } - static Border getCategoryBorder(Category category) { + static Border getCategoryBorder(DhsImageCategory category) { if (category != null) { switch (category) { case ONE: @@ -121,14 +121,14 @@ public interface DrawableView { } @ThreadConfined(type = ThreadConfined.ThreadType.ANY) - default Category updateCategory() { + default DhsImageCategory updateCategory() { if (getFile().isPresent()) { - final Category category = getFile().map(DrawableFile::getCategory).orElse(Category.ZERO); - final Border border = hasHashHit() && (category == Category.ZERO) ? HASH_BORDER : getCategoryBorder(category); + final DhsImageCategory category = getFile().map(DrawableFile::getCategory).orElse(DhsImageCategory.ZERO); + final Border border = hasHashHit() && (category == DhsImageCategory.ZERO) ? HASH_BORDER : getCategoryBorder(category); Platform.runLater(() -> getCategoryBorderRegion().setBorder(border)); return category; } else { - return Category.ZERO; + return DhsImageCategory.ZERO; } } } diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java index 6fc8074248..169856ab88 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/GroupPane.java @@ -122,7 +122,7 @@ import org.sleuthkit.autopsy.imagegallery.actions.RedoAction; import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter; import org.sleuthkit.autopsy.imagegallery.actions.TagSelectedFilesAction; import org.sleuthkit.autopsy.imagegallery.actions.UndoAction; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.DrawableGroup; import org.sleuthkit.autopsy.imagegallery.datamodel.grouping.GroupViewMode; @@ -352,7 +352,7 @@ public class GroupPane extends BorderPane { return grouping.getReadOnlyProperty(); } - private ToggleButton getToggleForCategory(Category category) { + private ToggleButton getToggleForCategory(DhsImageCategory category) { switch (category) { case ZERO: return cat0Toggle; @@ -397,7 +397,7 @@ public class GroupPane extends BorderPane { assert slideShowToggle != null : "fx:id=\"segButton\" was not injected: check your FXML file 'GroupHeader.fxml'."; assert tileToggle != null : "fx:id=\"tileToggle\" was not injected: check your FXML file 'GroupHeader.fxml'."; - for (Category cat : Category.values()) { + for (DhsImageCategory cat : DhsImageCategory.values()) { ToggleButton toggleForCategory = getToggleForCategory(cat); toggleForCategory.setBorder(new Border(new BorderStroke(cat.getColor(), BorderStrokeStyle.SOLID, CORNER_RADII_2, BORDER_WIDTHS_2))); toggleForCategory.getStyleClass().remove("radio-button"); @@ -445,13 +445,13 @@ public class GroupPane extends BorderPane { }); - CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(Category.FIVE, controller); + CategorizeSelectedFilesAction cat5SelectedAction = new CategorizeSelectedFilesAction(DhsImageCategory.FIVE, controller); catSelectedSplitMenu.setOnAction(cat5SelectedAction); catSelectedSplitMenu.setText(cat5SelectedAction.getText()); catSelectedSplitMenu.setGraphic(cat5SelectedAction.getGraphic()); catSelectedSplitMenu.showingProperty().addListener(showing -> { if (catSelectedSplitMenu.isShowing()) { - List categoryMenues = Lists.transform(Arrays.asList(Category.values()), + List categoryMenues = Lists.transform(Arrays.asList(DhsImageCategory.values()), cat -> GuiUtils.createAutoAssigningMenuItem(catSelectedSplitMenu, new CategorizeSelectedFilesAction(cat, controller))); catSelectedSplitMenu.getItems().setAll(categoryMenues); } @@ -765,7 +765,7 @@ public class GroupPane extends BorderPane { } ObservableSet selected = selectionModel.getSelected(); if (selected.isEmpty() == false) { - Category cat = keyCodeToCat(t.getCode()); + DhsImageCategory cat = keyCodeToCat(t.getCode()); if (cat != null) { new CategorizeAction(controller, cat, selected).handle(null); } @@ -773,27 +773,27 @@ public class GroupPane extends BorderPane { } } - private Category keyCodeToCat(KeyCode t) { + private DhsImageCategory keyCodeToCat(KeyCode t) { if (t != null) { switch (t) { case NUMPAD0: case DIGIT0: - return Category.ZERO; + return DhsImageCategory.ZERO; case NUMPAD1: case DIGIT1: - return Category.ONE; + return DhsImageCategory.ONE; case NUMPAD2: case DIGIT2: - return Category.TWO; + return DhsImageCategory.TWO; case NUMPAD3: case DIGIT3: - return Category.THREE; + return DhsImageCategory.THREE; case NUMPAD4: case DIGIT4: - return Category.FOUR; + return DhsImageCategory.FOUR; case NUMPAD5: case DIGIT5: - return Category.FIVE; + return DhsImageCategory.FIVE; } } return null; diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java index bf6597ecb5..60f30564b1 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/MetaDataPane.java @@ -57,7 +57,7 @@ import org.sleuthkit.autopsy.casemodule.events.ContentTagDeletedEvent; import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.CategoryManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; @@ -171,7 +171,7 @@ public class MetaDataPane extends DrawableUIBase { if (p.getKey() == DrawableAttribute.TAGS) { return ((Collection) p.getValue()).stream() .map(TagName::getDisplayName) - .filter(Category::isNotCategoryName) + .filter(DhsImageCategory::isNotCategoryName) .collect(Collectors.joining(" ; ")); } else { return p.getValue().stream() diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java index 94e56cf93c..11d109bbb5 100755 --- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java +++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/gui/drawableviews/SlideShowView.java @@ -50,7 +50,7 @@ import org.sleuthkit.autopsy.coreutils.ThreadConfined; import org.sleuthkit.autopsy.coreutils.ThreadConfined.ThreadType; import org.sleuthkit.autopsy.imagegallery.FXMLConstructor; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; -import org.sleuthkit.autopsy.imagegallery.datamodel.Category; +import org.sleuthkit.autopsy.datamodel.DhsImageCategory; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile; import org.sleuthkit.autopsy.imagegallery.datamodel.VideoFile; import org.sleuthkit.autopsy.imagegallery.gui.VideoPlayer; @@ -306,14 +306,14 @@ public class SlideShowView extends DrawableTileBase { */ @Override @ThreadConfined(type = ThreadType.ANY) - public Category updateCategory() { + public DhsImageCategory updateCategory() { Optional file = getFile(); if (file.isPresent()) { - Category updateCategory = super.updateCategory(); + DhsImageCategory updateCategory = super.updateCategory(); Platform.runLater(() -> getGroupPane().syncCatToggle(file.get())); return updateCategory; } else { - return Category.ZERO; + return DhsImageCategory.ZERO; } } diff --git a/InternalPythonModules/android/browserlocation.py b/InternalPythonModules/android/browserlocation.py index ef79a623c2..6db230c2e6 100755 --- a/InternalPythonModules/android/browserlocation.py +++ b/InternalPythonModules/android/browserlocation.py @@ -28,6 +28,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -89,14 +90,16 @@ class BrowserLocationAnalyzer(general.AndroidComponentAnalyzer): latitude = Double.valueOf(resultSet.getString("latitude")) longitude = Double.valueOf(resultSet.getString("longitude")) + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Browser Location History")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Browser Location History")) # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy)) # NOTE: originally commented out + artifact.addAttributes(attributes); try: # index the artifact for keyword search blackboard = Case.getCurrentCase().getServices().getBlackboard() diff --git a/InternalPythonModules/android/cachelocation.py b/InternalPythonModules/android/cachelocation.py index c28aa48fc3..019c03c654 100755 --- a/InternalPythonModules/android/cachelocation.py +++ b/InternalPythonModules/android/cachelocation.py @@ -25,6 +25,7 @@ from java.lang import ClassNotFoundException from java.math import BigInteger from java.nio import ByteBuffer from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -120,13 +121,15 @@ class CacheLocationAnalyzer(general.AndroidComponentAnalyzer): inputStream.read(tempBytes) timestamp = BigInteger(tempBytes).longValue() / 1000 + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME, + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME, file.getName() + "Location History")) + artifact.addAttributes(attributes) #Not storing these for now. # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), AndroidModuleFactorymodule.moduleName, accuracy)) # artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), AndroidModuleFactorymodule.moduleName, confidence)) diff --git a/InternalPythonModules/android/calllog.py b/InternalPythonModules/android/calllog.py index 42e3a293a1..6b9cb956d8 100755 --- a/InternalPythonModules/android/calllog.py +++ b/InternalPythonModules/android/calllog.py @@ -28,6 +28,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -119,17 +120,19 @@ class CallLogAnalyzer(general.AndroidComponentAnalyzer): name = resultSet.getString("name") # name of person dialed or called. None if unregistered try: + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) # create a call log and then add attributes from result set. if direction == CallLogAnalyzer.OUTGOING: - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, number)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, number)) else: # Covers INCOMING and MISSED - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, number)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, number)) - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, general.MODULE_NAME, date)) - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, general.MODULE_NAME, duration + date)) - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, directionString)) - artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, general.MODULE_NAME, date)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, general.MODULE_NAME, duration + date)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, directionString)) + attributes.add(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) + artifact.addAttributes(attributes) bbartifacts.append(artifact) try: diff --git a/InternalPythonModules/android/contact.py b/InternalPythonModules/android/contact.py index fe56cc1cbb..22eb681061 100755 --- a/InternalPythonModules/android/contact.py +++ b/InternalPythonModules/android/contact.py @@ -27,6 +27,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -118,6 +119,7 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer): + "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" + "ORDER BY raw_contacts.display_name ASC;") + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) oldName = "" while resultSet.next(): @@ -126,14 +128,15 @@ class ContactAnalyzer(general.AndroidComponentAnalyzer): mimetype = resultSet.getString("mimetype") # either phone or email if name != oldName: artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name)) if mimetype == "vnd.android.cursor.item/phone_v2": - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1)) else: - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1)) oldName = name + artifact.addAttributes(attributes) bbartifacts.append(artifact) try: diff --git a/InternalPythonModules/android/googlemaplocation.py b/InternalPythonModules/android/googlemaplocation.py index 066ed2f792..444c0477ee 100755 --- a/InternalPythonModules/android/googlemaplocation.py +++ b/InternalPythonModules/android/googlemaplocation.py @@ -28,6 +28,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -96,17 +97,19 @@ class GoogleMapLocationAnalyzer(general.AndroidComponentAnalyzer): source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat")) source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng")) + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, general.MODULE_NAME, "Destination")) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, time)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, general.MODULE_NAME, dest_lat)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, general.MODULE_NAME, dest_lng)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, general.MODULE_NAME, source_lat)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, general.MODULE_NAME, source_lng)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, dest_title)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, general.MODULE_NAME, dest_address)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Google Maps History")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, general.MODULE_NAME, "Destination")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, time)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, general.MODULE_NAME, dest_lat)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, general.MODULE_NAME, dest_lng)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, general.MODULE_NAME, source_lat)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, general.MODULE_NAME, source_lng)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, dest_title)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, general.MODULE_NAME, dest_address)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Google Maps History")) + artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase().getServices().getBlackboard() diff --git a/InternalPythonModules/android/tangomessage.py b/InternalPythonModules/android/tangomessage.py index 04223f7fe1..9a792064da 100755 --- a/InternalPythonModules/android/tangomessage.py +++ b/InternalPythonModules/android/tangomessage.py @@ -28,6 +28,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.apache.commons.codec.binary import Base64 from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard @@ -94,12 +95,14 @@ class TangoMessageAnalyzer(general.AndroidComponentAnalyzer): direction = "Outgoing" payload = resultSet.getString("payload") + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) #create a call log and then add attributes from result set. - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, create_time)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, direction)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, TangoMessageAnalyzer.decodeMessage(conv_id, payload))) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Tango Message")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, create_time)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, direction)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, TangoMessageAnalyzer.decodeMessage(conv_id, payload))) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Tango Message")) + artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase().getServices().getBlackboard() diff --git a/InternalPythonModules/android/textmessage.py b/InternalPythonModules/android/textmessage.py index afca23cdf1..55bb563fea 100755 --- a/InternalPythonModules/android/textmessage.py +++ b/InternalPythonModules/android/textmessage.py @@ -28,6 +28,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -92,19 +93,21 @@ class TextMessageAnalyzer(general.AndroidComponentAnalyzer): read = resultSet.getInt("read") # may be unread = 0, read = 1 subject = resultSet.getString("subject") # message subject body = resultSet.getString("body") # message body + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set. if resultSet.getString("type") == "1": - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Incoming")) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, address)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Incoming")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, address)) else: - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Outgoing")) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, address)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, date)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, general.MODULE_NAME, Integer(read))) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Outgoing")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, address)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, date)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, general.MODULE_NAME, Integer(read))) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message")) + artifact.addAttributes(attributes) bbartifacts.append(artifact) try: # index the artifact for keyword search diff --git a/InternalPythonModules/android/wwfmessage.py b/InternalPythonModules/android/wwfmessage.py index 97f35869ed..e880cc1759 100755 --- a/InternalPythonModules/android/wwfmessage.py +++ b/InternalPythonModules/android/wwfmessage.py @@ -26,6 +26,7 @@ from java.sql import ResultSet from java.sql import SQLException from java.sql import Statement from java.util.logging import Level +from java.util import ArrayList from org.sleuthkit.autopsy.casemodule import Case from org.sleuthkit.autopsy.casemodule.services import Blackboard from org.sleuthkit.autopsy.casemodule.services import FileManager @@ -88,13 +89,15 @@ class WWFMessageAnalyzer(general.AndroidComponentAnalyzer): user_id = resultSet.getString("user_id") # the ID of the user who sent the message. game_id = resultSet.getString("game_id") # ID of the game which the the message was sent. + attributes = ArrayList() artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) # create a call log and then add attributes from result set. - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, created_at)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, user_id)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message)) - artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message")) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, created_at)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, user_id)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message)) + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message")) + artifact.addAttributes(attributes) try: # index the artifact for keyword search blackboard = Case.getCurrentCase().getServices().getBlackboard() diff --git a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java index d22ce2ca76..b0af801089 100755 --- a/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java +++ b/RecentActivity/src/org/sleuthkit/autopsy/recentactivity/ExtractRegistry.java @@ -649,14 +649,15 @@ class ExtractRegistry extends Extract { String homeDir = value; String sid = artnode.getAttribute("sid"); //NON-NLS String username = artnode.getAttribute("username"); //NON-NLS - BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_OS_ACCOUNT); - bbart.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_NAME, parentModuleName, username)); - bbart.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID, + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_USER_ID, parentModuleName, sid)); - bbart.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PATH, parentModuleName, homeDir)); + + bbart.addAttributes(bbattributes); // index the artifact for keyword search this.indexArtifact(bbart); } catch (TskCoreException ex) { @@ -669,10 +670,11 @@ class ExtractRegistry extends Extract { String localPath = artnode.getAttribute("localPath"); //NON-NLS String remoteName = value; BlackboardArtifact bbart = regFile.newArtifact(ARTIFACT_TYPE.TSK_REMOTE_DRIVE); - bbart.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCAL_PATH, + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_LOCAL_PATH, parentModuleName, localPath)); - bbart.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH, + bbattributes.add(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_REMOTE_PATH, parentModuleName, remoteName)); + bbart.addAttributes(bbattributes); // index the artifact for keyword search this.indexArtifact(bbart); } catch (TskCoreException ex) { diff --git a/pythonExamples/Aug2015DataSourceTutorial/FindContactsDb.py b/pythonExamples/Aug2015DataSourceTutorial/FindContactsDb.py index 7a11ed913d..2aa5d9d9a4 100755 --- a/pythonExamples/Aug2015DataSourceTutorial/FindContactsDb.py +++ b/pythonExamples/Aug2015DataSourceTutorial/FindContactsDb.py @@ -40,6 +40,7 @@ from java.lang import Class from java.lang import System from java.sql import DriverManager, SQLException from java.util.logging import Level +from java.util import ArrayList from java.io import File from org.sleuthkit.datamodel import SleuthkitCase from org.sleuthkit.datamodel import AbstractFile @@ -162,17 +163,18 @@ class ContactsDbIngestModule(DataSourceIngestModule): # Make an artifact on the blackboard, TSK_CONTACT and give it attributes for each of the fields art = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT) - - art.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID(), + attributes = ArrayList() + + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME_PERSON.getTypeID(), ContactsDbIngestModuleFactory.moduleName, name)) - art.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID(), + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL.getTypeID(), ContactsDbIngestModuleFactory.moduleName, email)) - art.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(), + attributes.add(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(), ContactsDbIngestModuleFactory.moduleName, phone)) - - + + art.addAttributes(attributes) try: # index the artifact for keyword search blackboard.indexArtifact(art) @@ -195,4 +197,4 @@ class ContactsDbIngestModule(DataSourceIngestModule): "ContactsDb Analyzer", "Found %d files" % fileCount) IngestServices.getInstance().postMessage(message) - return IngestModule.ProcessResult.OK \ No newline at end of file + return IngestModule.ProcessResult.OK