diff --git a/Core/ivy.xml b/Core/ivy.xml
index c3afd23afa..35cb8de904 100755
--- a/Core/ivy.xml
+++ b/Core/ivy.xml
@@ -16,6 +16,7 @@
+
diff --git a/Core/nbproject/project.properties b/Core/nbproject/project.properties
index bf9045dea8..b6931ff315 100755
--- a/Core/nbproject/project.properties
+++ b/Core/nbproject/project.properties
@@ -1,5 +1,6 @@
file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar
file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
+file.reference.commons-compress-1.12.jar=release/modules/ext/commons-compress-1.12.jar
file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
@@ -7,7 +8,7 @@ file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jsoup-1.10.3.jar=release/modules/ext/jsoup-1.10.3.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.jar
file.reference.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
-file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar
+file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar
file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
@@ -16,6 +17,7 @@ file.reference.sevenzipjbinding.jar=release/modules/ext/sevenzipjbinding.jar
file.reference.sqlite-jdbc-3.8.11.jar=release/modules/ext/sqlite-jdbc-3.8.11.jar
file.reference.StixLib.jar=release/modules/ext/StixLib.jar
file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar
+file.reference.tika-parsers-1.14.jar=release/modules/ext/tika-parsers-1.14.jar
file.reference.Tsk_DataModel_PostgreSQL.jar=release/modules/ext/Tsk_DataModel_PostgreSQL.jar
file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
@@ -24,12 +26,10 @@ file.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8
file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial
-javadoc.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip
license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier
nbm.needs.restart=true
-source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.9
diff --git a/Core/nbproject/project.xml b/Core/nbproject/project.xml
index ec8c304f37..c4fea0885c 100755
--- a/Core/nbproject/project.xml
+++ b/Core/nbproject/project.xml
@@ -304,16 +304,15 @@
org.sleuthkit.autopsy.corecomponents
org.sleuthkit.autopsy.coreutils
org.sleuthkit.autopsy.datamodel
- org.sleuthkit.autopsy.datamodel.tags
org.sleuthkit.autopsy.datasourceprocessors
org.sleuthkit.autopsy.directorytree
org.sleuthkit.autopsy.events
- org.sleuthkit.autopsy.externalresults
org.sleuthkit.autopsy.filesearch
org.sleuthkit.autopsy.guiutils
org.sleuthkit.autopsy.ingest
org.sleuthkit.autopsy.keywordsearchservice
org.sleuthkit.autopsy.menuactions
+ org.sleuthkit.autopsy.modules.encryptiondetection
org.sleuthkit.autopsy.modules.filetypeid
org.sleuthkit.autopsy.modules.hashdatabase
org.sleuthkit.autopsy.modules.vmextractor
@@ -337,25 +336,13 @@
ext/tika-core-1.14.jar
release/modules/ext/tika-core-1.14.jar
-
- ext/StixLib.jar
- release/modules/ext/StixLib.jar
-
ext/Tsk_DataModel_PostgreSQL.jar
release/modules/ext/Tsk_DataModel_PostgreSQL.jar
-
+
- ext/curator-client-2.8.0.jar
- release/modules/ext/curator-client-2.8.0.jar
-
-
- ext/sqlite-jdbc-3.8.11.jar
- release/modules/ext/sqlite-jdbc-3.8.11.jar
-
-
- ext/activemq-all-5.11.1.jar
- release/modules/ext/activemq-all-5.11.1.jar
+ ext/StixLib.jar
+ release/modules/ext/StixLib.jar
ext/opencv-248.jar
@@ -365,18 +352,30 @@
ext/curator-framework-2.8.0.jar
release/modules/ext/curator-framework-2.8.0.jar
+
+ ext/curator-client-2.8.0.jar
+ release/modules/ext/curator-client-2.8.0.jar
+
ext/commons-dbcp2-2.1.1.jar
release\modules\ext\commons-dbcp2-2.1.1.jar
- ext/Rejistry-1.0-SNAPSHOT.jar
- release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
+ ext/tika-parsers-1.14.jar
+ release/modules/ext/tika-parsers-1.14.jar
ext/jython-standalone-2.7.0.jar
release/modules/ext/jython-standalone-2.7.0.jar
+
+ ext/activemq-all-5.11.1.jar
+ release/modules/ext/activemq-all-5.11.1.jar
+
+
+ ext/opencv-248.jar
+ release/modules/ext/opencv-248.jar
+
ext/sevenzipjbinding.jar
release/modules/ext/sevenzipjbinding.jar
@@ -385,26 +384,6 @@
ext/mchange-commons-java-0.2.9.jar
release/modules/ext/mchange-commons-java-0.2.9.jar
-
- ext/sevenzipjbinding-AllPlatforms.jar
- release/modules/ext/sevenzipjbinding-AllPlatforms.jar
-
-
- ext/commons-pool2-2.4.2.jar
- release\modules\ext\commons-pool2-2.4.2.jar
-
-
- ext/metadata-extractor-2.8.1.jar
- release/modules/ext/metadata-extractor-2.8.1.jar
-
-
- ext/jsoup-1.10.3.jar
- release/modules/ext/jsoup-1.10.3.jar
-
-
- ext/jdom-2.0.5-contrib.jar
- release/modules/ext/jdom-2.0.5-contrib.jar
-
ext/postgresql-9.4.1211.jre7.jar
release/modules/ext/postgresql-9.4.1211.jre7.jar
@@ -414,17 +393,53 @@
release/modules/ext/curator-recipes-2.8.0.jar
- ext/c3p0-0.9.5.jar
- release/modules/ext/c3p0-0.9.5.jar
+ ext/xmpcore-5.1.2.jar
+ release/modules/ext/xmpcore-5.1.2.jar
- ext/commons-dbcp2-2.1.1.jar
- release\modules\ext\commons-dbcp2-2.1.1.jar
+ ext/sevenzipjbinding-AllPlatforms.jar
+ release/modules/ext/sevenzipjbinding-AllPlatforms.jar
ext/commons-pool2-2.4.2.jar
release\modules\ext\commons-pool2-2.4.2.jar
+
+ ext/sqlite-jdbc-3.8.11.jar
+ release/modules/ext/sqlite-jdbc-3.8.11.jar
+
+
+ ext/activemq-all-5.11.1.jar
+ release/modules/ext/activemq-all-5.11.1.jar
+
+
+ ext/jsoup-1.10.3.jar
+ release/modules/ext/jsoup-1.10.3.jar
+
+
+ ext/Rejistry-1.0-SNAPSHOT.jar
+ release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
+
+
+ ext/metadata-extractor-2.9.1.jar
+ release/modules/ext/metadata-extractor-2.9.1.jar
+
+
+ ext/commons-compress-1.12.jar
+ release/modules/ext/commons-compress-1.12.jar
+
+
+ ext/jdom-2.0.5-contrib.jar
+ release/modules/ext/jdom-2.0.5-contrib.jar
+
+
+ ext/c3p0-0.9.5.jar
+ release/modules/ext/c3p0-0.9.5.jar
+
+
+ ext/c3p0-0.9.5.jar
+ release/modules/ext/c3p0-0.9.5.jar
+
diff --git a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
index f665aeb7d5..95b68b87d6 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 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");
@@ -26,12 +26,14 @@ import javax.swing.AbstractAction;
import javax.swing.JMenu;
import javax.swing.JMenuItem;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
/**
* An abstract base class for Actions that allow users to tag SleuthKit data
@@ -107,7 +109,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey();
- JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
+ String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
// for the bookmark tag name only, added shortcut label
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT);
@@ -122,7 +125,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags"));
empty.setEnabled(false);
quickTagMenu.add(empty);
- }
+ }
quickTagMenu.addSeparator();
@@ -155,10 +158,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
/**
* Method to add to the action listener for each menu item. Allows a tag
* display name to be added to the menu with an action listener without
- * having to instantiate a TagName object for it.
- * When the method is called, the TagName object is created here if it
- * doesn't already exist.
- *
+ * having to instantiate a TagName object for it. When the method is
+ * called, the TagName object is created here if it doesn't already
+ * exist.
+ *
* @param tagDisplayName display name for the tag name
* @param tagName TagName object associated with the tag name,
* may be null
diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
index 28d4e4006a..1cbc4b70b6 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
@@ -4,7 +4,7 @@ GetTagNameDialog.okButton.text=OK
GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names:
GetTagNameDialog.newTagPanel.border.title=New Tag
GetTagNameDialog.tagNameLabel.text=Tag Name:
-GetTagNameAndCommentDialog.newTagButton.text=New Tag Name
+GetTagNameAndCommentDialog.newTagButton.text=New Tag
GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
GetTagNameAndCommentDialog.commentText.text=
@@ -12,7 +12,6 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment:
# To change this template, choose Tools | Templates
# and open the template in the editor.
GetTagNameAndCommentDialog.cancelButton.text=Cancel
-GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
GetTagNameAndCommentDialog.tagLabel.text=Tag:
AddTagAction.bookmarkFile=Bookmark file
AddTagAction.quickTag=Quick Tag
@@ -45,3 +44,4 @@ ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}
CTL_OpenPythonModulesFolderAction=Python Plugins
+GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
diff --git a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties
index 195d12c695..d6f865ecf0 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties
+++ b/Core/src/org/sleuthkit/autopsy/actions/Bundle_ja.properties
@@ -8,7 +8,6 @@ GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044
GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a
GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
-GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e
GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a
AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
@@ -48,4 +47,5 @@ CTL_OpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c
OpenOutputFolder.error1=\u6b21\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
OpenOutputFolder.noCaseOpen=\u30aa\u30fc\u30d7\u30f3\u30b1\u30fc\u30b9\u304c\u306a\u3044\u306e\u3067\u3001\u4f5c\u696d\u4e2d\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u3042\u308a\u307e\u305b\u3093\u3002
GetTagNameDialog.illegalChars.msg=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\u3002\n\u6b21\u306e\u6587\u5b57\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\uff1a\\ \: * ? " < > |
-OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
\ No newline at end of file
+OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
+GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e
diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java
index d9fd5d364f..86696b0c63 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileBlackboardArtifactTagAction.java
@@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
- *
+ *
* Copyright 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.
@@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
/**
* Instances of this Action allow users to delete tags applied to blackboard
@@ -52,7 +53,7 @@ import org.sleuthkit.datamodel.TskCoreException;
"DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag"
})
public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup {
-
+
private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName());
private static final long serialVersionUID = 1L;
@@ -89,27 +90,27 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
}
@NbBundle.Messages({"# {0} - artifactID",
- "DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."})
+ "DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."})
protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) {
new SwingWorker() {
@Override
protected Void doInBackground() throws Exception {
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
-
+
// Pull the from the global context to avoid unnecessary calls
// to the database.
- final Collection selectedFilesList =
- new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
+ final Collection selectedFilesList
+ = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next();
-
+
try {
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
tagsManager.deleteBlackboardArtifactTag(artifactTag);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS
- Platform.runLater(() ->
- new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show()
+ Platform.runLater(()
+ -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show()
);
}
return null;
@@ -133,21 +134,21 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
* comment.
*/
@NbBundle.Messages({"# {0} - artifactID",
- "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."})
+ "DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."})
private class TagMenu extends JMenu {
private static final long serialVersionUID = 1L;
TagMenu() {
super(getActionDisplayName());
-
- final Collection selectedBlackboardArtifactsList =
- new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
-
- if(!selectedBlackboardArtifactsList.isEmpty()) {
- BlackboardArtifact artifact =
- selectedBlackboardArtifactsList.iterator().next();
-
+
+ final Collection selectedBlackboardArtifactsList
+ = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
+
+ if (!selectedBlackboardArtifactsList.isEmpty()) {
+ BlackboardArtifact artifact
+ = selectedBlackboardArtifactsList.iterator().next();
+
// Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
@@ -163,17 +164,18 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
// a tag with the associated tag name.
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
try {
- List existingTagsList =
- Case.getCurrentCase().getServices().getTagsManager()
- .getBlackboardArtifactTagsByArtifact(artifact);
+ List existingTagsList
+ = Case.getCurrentCase().getServices().getTagsManager()
+ .getBlackboardArtifactTagsByArtifact(artifact);
for (Map.Entry entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey();
TagName tagName = entry.getValue();
- for(BlackboardArtifactTag artifactTag : existingTagsList) {
- if(tagDisplayName.equals(artifactTag.getName().getDisplayName())) {
- JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
+ for (BlackboardArtifactTag artifactTag : existingTagsList) {
+ if (tagDisplayName.equals(artifactTag.getName().getDisplayName())) {
+ String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, artifactTag, artifact.getArtifactID());
});
@@ -187,7 +189,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
}
}
- if(getItemCount() == 0) {
+ if (getItemCount() == 0) {
setEnabled(false);
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java
index e49e0f9170..5c8d4abb74 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java
@@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
/**
* Instances of this Action allow users to delete tags applied to content.
@@ -169,7 +170,8 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen
TagName tagName = entry.getValue();
for(ContentTag contentTag : existingTagsList) {
if(tagDisplayName.equals(contentTag.getName().getDisplayName())) {
- JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
+ String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, contentTag, file.getId());
});
diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form
index 17a9738dbd..57c43e964b 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form
+++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.form
@@ -28,7 +28,7 @@
-
+
@@ -39,11 +39,10 @@
-
+
-
+
-
@@ -108,8 +107,8 @@
-
-
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java
index 647d851341..e01a887949 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameAndCommentDialog.java
@@ -1,15 +1,15 @@
/*
* 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");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
- *
+ *
* http://www.apache.org/licenses/LICENSE-2.0
- *
+ *
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@@ -18,17 +18,20 @@
*/
package org.sleuthkit.autopsy.actions;
+import java.awt.Component;
import java.awt.Window;
import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent;
-import java.util.Map;
-import java.util.TreeMap;
import java.util.logging.Level;
+import java.util.HashSet;
+import java.util.Set;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
+import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog;
+import javax.swing.JList;
import javax.swing.KeyStroke;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
@@ -37,15 +40,14 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
public class GetTagNameAndCommentDialog extends JDialog {
private static final long serialVersionUID = 1L;
- private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class,
- "GetTagNameAndCommentDialog.noTags");
- private final Map tagNamesMap = new TreeMap<>();
+ private final Set tagNamesSet = new HashSet<>();
private TagNameAndComment tagNameAndComment = null;
-
+
public static class TagNameAndComment {
private final TagName tagName;
@@ -68,7 +70,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
/**
* Show the Tag Name and Comment Dialog and return the TagNameAndContent
* chosen by the user. The dialog will be centered with the main autopsy
- * window as its owner.
+ * window as its owner.
*
* @return a TagNameAndComment instance containing the TagName selected by
* the user and the entered comment, or null if the user canceled
@@ -102,21 +104,34 @@ public class GetTagNameAndCommentDialog extends JDialog {
ModalityType.APPLICATION_MODAL);
}
+
private void display() {
initComponents();
-
+ tagCombo.setRenderer(new DefaultListCellRenderer() {
+ private static final long serialVersionUID = 1L;
+ @Override
+ public Component getListCellRendererComponent(JList> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
+ String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ?TagsManager.getNotableTagLabel() : "";
+ String newValue = ((TagName) value).getDisplayName() + status;
+ return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus);
+ }
+ });
// Set up the dialog to close when Esc is pressed.
String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameAndCommentDialog.cancelName");
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
+
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap();
+
actionMap.put(cancelName, new AbstractAction() {
private static final long serialVersionUID = 1L;
+
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
- });
+ }
+ );
// Populate the combo box with the available tag names and save the
// tag name DTOs to be enable to return the one the user selects.
@@ -124,23 +139,22 @@ public class GetTagNameAndCommentDialog extends JDialog {
// not exist in the database).
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
try {
- tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap());
+ tagNamesSet.addAll(tagsManager.getAllTagNames());
+
} catch (TskCoreException ex) {
- Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
+ Logger.getLogger(GetTagNameAndCommentDialog.class
+ .getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
}
- if (null != tagNamesMap && tagNamesMap.isEmpty()) {
- tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
- } else {
- for (String tagDisplayName : tagNamesMap.keySet()) {
- tagCombo.addItem(tagDisplayName);
- }
+ for (TagName tag : tagNamesSet) {
+
+ tagCombo.addItem(tag);
}
// Center and show the dialog box.
this.setLocationRelativeTo(this.getOwner());
- setVisible(true);
+ 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
@@ -152,7 +166,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton();
- tagCombo = new javax.swing.JComboBox();
+ tagCombo = new javax.swing.JComboBox();
tagLabel = new javax.swing.JLabel();
commentLabel = new javax.swing.JLabel();
commentText = new javax.swing.JTextField();
@@ -203,7 +217,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(newTagButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 165, Short.MAX_VALUE)
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton))
@@ -212,10 +226,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addComponent(commentLabel)
.addComponent(tagLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(commentText)
- .addComponent(tagCombo, 0, 214, Short.MAX_VALUE))
- .addGap(0, 0, Short.MAX_VALUE)))
+ .addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addContainerGap())
);
@@ -246,21 +259,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
}// //GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
- String tagDisplayName = (String) tagCombo.getSelectedItem();
- TagName tagNameFromCombo = tagNamesMap.get(tagDisplayName);
- if (tagNameFromCombo == null) {
- try {
- tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
- } catch (TagsManager.TagNameAlreadyExistsException ex) {
- try {
- tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagDisplayName);
- } catch (TskCoreException ex1) {
- Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database but an error occurred in retrieving it.", ex1); //NON-NLS
- }
- } catch (TskCoreException ex) {
- Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
- }
- }
+ TagName tagNameFromCombo = (TagName) tagCombo.getSelectedItem();
tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText());
dispose();
}//GEN-LAST:event_okButtonActionPerformed
@@ -278,9 +277,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
TagName newTagName = GetTagNameDialog.doDialog(this);
if (newTagName != null) {
- tagNamesMap.put(newTagName.getDisplayName(), newTagName);
- tagCombo.addItem(newTagName.getDisplayName());
- tagCombo.setSelectedItem(newTagName.getDisplayName());
+ tagNamesSet.add(newTagName);
+ tagCombo.addItem(newTagName);
+ tagCombo.setSelectedItem(newTagName);
}
}//GEN-LAST:event_newTagButtonActionPerformed
@@ -290,7 +289,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
private javax.swing.JTextField commentText;
private javax.swing.JButton newTagButton;
private javax.swing.JButton okButton;
- private javax.swing.JComboBox tagCombo;
+ private javax.swing.JComboBox tagCombo;
private javax.swing.JLabel tagLabel;
// End of variables declaration//GEN-END:variables
}
diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form
index a281ea606e..bf17a398a7 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form
+++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.form
@@ -142,11 +142,20 @@
-
+
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
@@ -154,12 +163,17 @@
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
@@ -182,6 +196,38 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java
index 4e5720a0fc..515db21dab 100755
--- a/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/actions/GetTagNameDialog.java
@@ -1,15 +1,15 @@
/*
* 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.
@@ -36,13 +36,17 @@ import javax.swing.KeyStroke;
import javax.swing.table.AbstractTableModel;
import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle;
+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.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
+@Messages({"GetTagNameDialog.descriptionLabel.text=Description:",
+ "GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
public class GetTagNameDialog extends JDialog {
private static final long serialVersionUID = 1L;
@@ -79,7 +83,7 @@ public class GetTagNameDialog extends JDialog {
}
private GetTagNameDialog(Window owner) {
- super(owner,
+ super(owner,
NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"),
ModalityType.APPLICATION_MODAL);
}
@@ -95,7 +99,7 @@ public class GetTagNameDialog extends JDialog {
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() {
private static final long serialVersionUID = 1L;
-
+
@Override
public void actionPerformed(ActionEvent e) {
cancelButtonActionPerformed(e);
@@ -120,9 +124,9 @@ public class GetTagNameDialog extends JDialog {
// Center and show the dialog box.
this.setLocationRelativeTo(this.getOwner());
- setVisible(true);
+ setVisible(true);
}
-
+
private class TagsTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L;
@@ -172,6 +176,10 @@ public class GetTagNameDialog extends JDialog {
newTagPanel = new javax.swing.JPanel();
tagNameLabel = new javax.swing.JLabel();
tagNameField = new javax.swing.JTextField();
+ descriptionLabel = new javax.swing.JLabel();
+ descriptionScrollPane = new javax.swing.JScrollPane();
+ descriptionTextArea = new javax.swing.JTextArea();
+ notableCheckbox = new javax.swing.JCheckBox();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
addKeyListener(new java.awt.event.KeyAdapter() {
@@ -223,25 +231,46 @@ public class GetTagNameDialog extends JDialog {
}
});
+ org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.descriptionLabel.text")); // NOI18N
+
+ descriptionTextArea.setColumns(20);
+ descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
+ descriptionTextArea.setRows(3);
+ descriptionScrollPane.setViewportView(descriptionTextArea);
+
+ org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.notableCheckbox.text")); // NOI18N
+
javax.swing.GroupLayout newTagPanelLayout = new javax.swing.GroupLayout(newTagPanel);
newTagPanel.setLayout(newTagPanelLayout);
newTagPanelLayout.setHorizontalGroup(
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newTagPanelLayout.createSequentialGroup()
.addContainerGap()
- .addComponent(tagNameLabel)
- .addGap(36, 36, 36)
- .addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 235, Short.MAX_VALUE)
+ .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(descriptionScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 323, Short.MAX_VALUE)
+ .addGroup(newTagPanelLayout.createSequentialGroup()
+ .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(notableCheckbox)
+ .addComponent(descriptionLabel)
+ .addComponent(tagNameLabel))
+ .addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
);
newTagPanelLayout.setVerticalGroup(
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newTagPanelLayout.createSequentialGroup()
- .addContainerGap()
- .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(tagNameLabel)
- .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
- .addContainerGap(164, Short.MAX_VALUE))
+ .addGap(6, 6, 6)
+ .addComponent(tagNameLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .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)
+ .addContainerGap(31, Short.MAX_VALUE))
);
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
@@ -288,8 +317,14 @@ public class GetTagNameDialog extends JDialog {
dispose();
}//GEN-LAST:event_cancelButtonActionPerformed
+ @NbBundle.Messages({"GetTagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.",
+ "GetTagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name",
+ "GetTagNameDialog.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)",
+ "GetTagNameDialog.tagDescriptionIllegalCharacters.title=Invalid character in tag description"})
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String tagDisplayName = tagNameField.getText();
+ String userTagDescription = descriptionTextArea.getText();
+ TskData.FileKnown status = notableCheckbox.isSelected() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
if (tagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
@@ -301,11 +336,18 @@ public class GetTagNameDialog extends JDialog {
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"),
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"),
JOptionPane.ERROR_MESSAGE);
+ } else if (userTagDescription.contains(",")
+ || userTagDescription.contains(";")) {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.message"),
+ NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.title"),
+ JOptionPane.ERROR_MESSAGE);
} else {
tagName = tagNamesMap.get(tagDisplayName);
+
if (tagName == null) {
try {
- tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
+ tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName, userTagDescription, TagName.HTML_COLOR.NONE, status);
dispose();
} catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
@@ -331,7 +373,10 @@ public class GetTagNameDialog extends JDialog {
}
}
} else {
- dispose();
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.message"),
+ NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.title"),
+ JOptionPane.INFORMATION_MESSAGE);
}
}
}//GEN-LAST:event_okButtonActionPerformed
@@ -350,8 +395,12 @@ public class GetTagNameDialog extends 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.JScrollPane jScrollPane1;
private javax.swing.JPanel newTagPanel;
+ private javax.swing.JCheckBox notableCheckbox;
private javax.swing.JButton okButton;
private javax.swing.JLabel preexistingLabel;
private javax.swing.JTextField tagNameField;
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java
index b2d14db118..c610ff78c3 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/AddLocalFilesTask.java
@@ -89,7 +89,7 @@ class AddLocalFilesTask implements Runnable {
progress.setIndeterminate(true);
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
LocalFilesDataSource newDataSource = fileManager.addLocalFilesDataSource(deviceId, rootVirtualDirectoryName, "", localFilePaths, new ProgressUpdater());
- newDataSources.add(newDataSource.getRootDirectory());
+ newDataSources.add(newDataSource);
} catch (TskDataException | TskCoreException ex) {
errors.add(ex.getMessage());
LOGGER.log(Level.SEVERE, String.format("Failed to add datasource: %s", ex.getMessage()), ex);
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
index 00ce2cca5d..e2e58c5b5a 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/Case.java
@@ -363,7 +363,14 @@ public class Case {
* case number, the examiner name, examiner phone, examiner email, and
* the case notes.
*/
- CASE_DETAILS;
+ CASE_DETAILS,
+ /**
+ * A tag definition has changed (e.g., description, known status). The
+ * old value of the PropertyChangeEvent is the display name of the tag
+ * definition that has changed.
+ */
+ TAG_DEFINITION_CHANGED;
+
};
/**
@@ -1463,6 +1470,18 @@ public class Case {
eventPublisher.publish(new ContentTagDeletedEvent(deletedTag));
}
+ /**
+ * Notifies case event subscribers that a tag definition has changed.
+ *
+ * This should not be called from the event dispatch thread (EDT)
+ *
+ * @param changedTagName the name of the tag definition which was changed
+ */
+ public void notifyTagDefinitionChanged(String changedTagName) {
+ //leaving new value of changedTagName as null, because we do not currently support changing the display name of a tag.
+ eventPublisher.publish(new AutopsyEvent(Events.TAG_DEFINITION_CHANGED.toString(), changedTagName, null));
+ }
+
/**
* Notifies case event subscribers that an artifact tag has been added.
*
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java
index 23e9d0b1c8..101f8688dd 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/CasePropertiesPanel.java
@@ -78,10 +78,9 @@ final class CasePropertiesPanel extends javax.swing.JPanel {
try {
EamDb dbManager = EamDb.getInstance();
if (dbManager != null) {
- CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
if (null == correlationCase) {
- dbManager.newCase(Case.getCurrentCase());
- correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ correlationCase = dbManager.newCase(Case.getCurrentCase());
}
currentOrg = correlationCase.getOrg();
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
index 7a4a1f7bf4..89d527fcc1 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/NewCaseWizardAction.java
@@ -91,7 +91,7 @@ final class NewCaseWizardAction extends CallableSystemAction {
if (EamDb.isEnabled()) { //if the eam is enabled we need to save the case organization information now
EamDb dbManager = EamDb.getInstance();
if (dbManager != null) {
- CorrelationCase cRCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase cRCase = dbManager.getCase(Case.getCurrentCase());
if (cRCase == null) {
cRCase = dbManager.newCase(Case.getCurrentCase());
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java
index a2793ec295..0a9649c45d 100644
--- a/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/OptionalCasePropertiesPanel.java
@@ -89,7 +89,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
if (currentCase != null) {
try {
EamDb dbManager = EamDb.getInstance();
- selectedOrg = dbManager.getCaseByUUID(currentCase.getName()).getOrg();
+ selectedOrg = dbManager.getCase(currentCase).getOrg();
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Unable to get Organization associated with the case from Central Repo", ex);
}
@@ -561,7 +561,7 @@ final class OptionalCasePropertiesPanel extends javax.swing.JPanel {
if (EamDb.isEnabled()) {
try {
EamDb dbManager = EamDb.getInstance();
- CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
if (caseDisplayNameTextField.isVisible()) {
correlationCase.setDisplayName(caseDisplayNameTextField.getText());
}
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties
index 0dd66e8c59..e9c1b5307c 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle.properties
@@ -1,16 +1,15 @@
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
+TagNameDialog.okButton.text=OK
+TagNameDialog.cancelButton.text=Cancel
+TagNameDialog.tagNameTextField.text=
+TagNameDialog.newTagNameLabel.text=Name:
diff --git a/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/casemodule/services/Bundle_ja.properties
index 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/FileManager.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
index f12c2f7e5d..817052619b 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/FileManager.java
@@ -47,7 +47,6 @@ import org.sleuthkit.datamodel.LocalFilesDataSource;
import org.sleuthkit.datamodel.TskDataException;
import org.apache.commons.lang3.StringUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
-import org.sleuthkit.datamodel.AbstractContent;
import org.sleuthkit.datamodel.CarvingResult;
import org.sleuthkit.datamodel.TskData;
@@ -409,10 +408,9 @@ public class FileManager implements Closeable {
*/
trans = caseDb.beginTransaction();
LocalFilesDataSource dataSource = caseDb.addLocalFilesDataSource(deviceId, rootDirectoryName, timeZone, trans);
- VirtualDirectory rootDirectory = dataSource.getRootDirectory();
List filesAdded = new ArrayList<>();
for (java.io.File localFile : localFiles) {
- AbstractFile fileAdded = addLocalFile(trans, rootDirectory, localFile, TskData.EncodingType.NONE, progressUpdater);
+ AbstractFile fileAdded = addLocalFile(trans, dataSource, localFile, TskData.EncodingType.NONE, progressUpdater);
if (null != fileAdded) {
filesAdded.add(fileAdded);
} else {
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..e1d81d2b65
--- /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 status 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;
+ }
+
+ /**
+ * The status which will be applied to items with this tag.
+ *
+ * @return a value of TskData.FileKnown which is associated with this tag
+ */
+ TskData.FileKnown getKnownStatus() {
+ return knownStatus;
+ }
+
+ /**
+ * 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;
+ }
+ boolean sameName = this.getDisplayName().equals(((TagNameDefinition) obj).getDisplayName());
+ boolean sameStatus = this.getKnownStatus().equals(((TagNameDefinition) obj).getKnownStatus());
+ return sameName && sameStatus;
+ }
+
+ /**
+ * 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 8c7d29baa3..0000000000
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDefiniton.java
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * 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 javax.annotation.concurrent.Immutable;
-import org.openide.util.Exceptions;
-import org.openide.util.NbBundle;
-import org.sleuthkit.autopsy.casemodule.Case;
-import org.sleuthkit.autopsy.coreutils.ModuleSettings;
-import org.sleuthkit.datamodel.TagName;
-import org.sleuthkit.autopsy.datamodel.tags.Category;
-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 TagNameDefiniton implements Comparable {
-
- @NbBundle.Messages({"TagNameDefiniton.predefTagNames.bookmark.text=Bookmark",
- "TagNameDefiniton.predefTagNames.followUp.text=Follow Up",
- "TagNameDefiniton.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.TagNameDefiniton_predefTagNames_notableItem_text(), Category.ONE.getDisplayName(), Category.TWO.getDisplayName(), Category.THREE.getDisplayName()); // NON-NLS
- private static final List STANDARD_TAG_DISPLAY_NAMES = Arrays.asList(Bundle.TagNameDefiniton_predefTagNames_bookmark_text(), Bundle.TagNameDefiniton_predefTagNames_followUp_text(),
- Bundle.TagNameDefiniton_predefTagNames_notableItem_text(), Category.ONE.getDisplayName(),
- Category.TWO.getDisplayName(), Category.THREE.getDisplayName(),
- Category.FOUR.getDisplayName(), Category.FIVE.getDisplayName());
- private final String displayName;
- private final String description;
- private final TagName.HTML_COLOR color;
- private final TskData.FileKnown knownStatusDenoted;
-
- /**
- * 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.
- */
- TagNameDefiniton(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) {
- this.displayName = displayName;
- this.description = description;
- this.color = color;
- this.knownStatusDenoted = 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 is the Notable status
- *
- * @return true if the Notable status is implied by this tag, false
- * otherwise.
- */
- boolean isNotable() {
- return knownStatusDenoted == 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(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() + "," + knownStatusDenoted.toString();
- }
-
- private TagName saveToCase(SleuthkitCase caseDb) {
- TagName tagName = null;
- try {
- tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatusDenoted);
- } catch (TskCoreException ex) {
- Exceptions.printStackTrace(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<>();
- List standardTags = new ArrayList<>(STANDARD_TAG_DISPLAY_NAMES); //modifiable copy of default tags list for us to keep track of which ones already exist
- String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
- if (null != setting && !setting.isEmpty()) {
- List tagNameTuples = Arrays.asList(setting.split(";"));
- List notableTags = 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
- notableTags.addAll(STANDARD_NOTABLE_TAG_DISPLAY_NAMES);
- } else { //otherwise use the list that was in the central repository properties file
- notableTags.addAll(Arrays.asList(badTagsStr.split(",")));
- }
- for (String tagNameTuple : tagNameTuples) { //for each tag listed in the tags properties file
- String[] tagNameAttributes = tagNameTuple.split(","); //get the attributes
- if (tagNameAttributes.length == 3) { //if there are only 3 attributes so Tags.properties does not contain any tag definitions with knownStatus
- standardTags.remove(tagNameAttributes[0]); //remove tag from default tags we need to create still
- if (notableTags.contains(tagNameAttributes[0])) { //if tag should be notable mark create it as such
- tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.BAD));
- } else { //otherwise create it as unknown
- tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.UNKNOWN)); //add the default value for that tag
- }
- } else if (tagNameAttributes.length == 4) { //if there are 4 attributes its a current list we can use the values present
- standardTags.remove(tagNameAttributes[0]); //remove tag from default tags we need to create still
- tagNames.add(new TagNameDefiniton(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.valueOf(tagNameAttributes[2]), TskData.FileKnown.valueOf(tagNameAttributes[3])));
- }
- }
- }
- for (String standardTagName : standardTags) { //create standard tags which should always exist which were not already created for whatever reason, such as upgrade
- if (STANDARD_NOTABLE_TAG_DISPLAY_NAMES.contains(standardTagName)) {
- tagNames.add(new TagNameDefiniton(standardTagName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.BAD));
- } else {
- tagNames.add(new TagNameDefiniton(standardTagName, "", TagName.HTML_COLOR.NONE, TskData.FileKnown.UNKNOWN));
- }
- }
- 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());
- 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/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..a88e25eb55 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 54%
rename from Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java
rename to Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java
index b7b2e66ebc..4949be2507 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/NewTagNameDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagNameDialog.java
@@ -1,20 +1,20 @@
/*
-* 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.
+ * 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;
@@ -28,11 +28,17 @@ 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;
+import org.sleuthkit.datamodel.TskData;
-final class NewTagNameDialog extends javax.swing.JDialog {
+@Messages({"TagNameDialog.descriptionLabel.text=Description:",
+ "TagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
+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 +48,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.getKnownStatus() == TskData.FileKnown.BAD);
+ tagNameTextField.setEnabled(false);
+ this.display();
+ }
+
/**
* Sets display settings for the dialog and adds appropriate listeners.
*/
@@ -56,7 +74,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 +99,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,47 +126,68 @@ 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.
*/
+ @Messages({"TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)",
+ "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title=Invalid character in tag description"})
private void doButtonAction(boolean okPressed) {
if (okPressed) {
String newTagDisplayName = tagNameTextField.getText().trim();
+ String descriptionText = descriptionTextArea.getText();
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 a tag name contains illegal characters and is not the name of one of the standard tags
- if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefiniton.getStandardTagNames().contains(newTagDisplayName)) {
+ 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.tagDescriptionIllegalCharacters.message"),
+ NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title"),
+ JOptionPane.ERROR_MESSAGE);
+ return;
+ } else if (descriptionText.contains(",")
+ || descriptionText.contains(";")) {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"),
+ NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.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() {
@@ -153,9 +195,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());
@@ -175,27 +217,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(3);
+ 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(
@@ -203,13 +258,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(
@@ -219,13 +280,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();
@@ -242,7 +306,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 c58201621a..8654d04598 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 @@
-
+
-
-
+
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
+
-
+
+
+
-
-
+
+
-
-
+
+
+
-
+
@@ -129,7 +137,7 @@
-
+
@@ -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 681cc95472..c5458d2f76 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagOptionsPanel.java
@@ -18,6 +18,10 @@
*/
package org.sleuthkit.autopsy.casemodule.services;
+import java.awt.EventQueue;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.util.HashSet;
import java.util.Set;
import java.util.TreeSet;
import javax.swing.DefaultListModel;
@@ -25,7 +29,10 @@ import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent;
import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.corecomponents.OptionsPanel;
+import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskData;
@@ -35,26 +42,50 @@ import org.sleuthkit.datamodel.TskData;
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;
+ private Set updatedStatusTags;
/**
- * Creates new form TagsManagerOptionsPanel
+ * Creates new form TagOptionsPanel
*/
TagOptionsPanel() {
tagTypesListModel = new DefaultListModel<>();
- tagTypes = new TreeSet<>(TagNameDefiniton.getTagNameDefinitions());
+ tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions());
+ updatedStatusTags = new HashSet<>();
initComponents();
customizeComponents();
}
+ @Messages({"TagOptionsPanel.panelDescriptionTextArea.text=Create and manage tags. "
+ + "Tags 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. "
+ + "Changing the status of a tag will only effect items in the current case.",
+ "TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running!",
+ "TagOptionsPanel.descriptionLabel.text=Tag Description:",
+ "TagOptionsPanel.notableYesOrNoLabel.text=",
+ "TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable: ",
+ "TagOptionsPanel.editTagNameButton.text=Edit Tag"})
+
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);
}
/**
@@ -67,31 +98,43 @@ 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();
tagTypesListLabel = new javax.swing.JLabel();
- jScrollPane1 = new javax.swing.JScrollPane();
+ TagNameScrollPane = new javax.swing.JScrollPane();
tagNamesList = new javax.swing.JList<>();
newTagNameButton = new javax.swing.JButton();
deleteTagNameButton = new javax.swing.JButton();
+ editTagNameButton = new javax.swing.JButton();
+ panelDescriptionScrollPane = new javax.swing.JScrollPane();
+ panelDescriptionTextArea = 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
tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION);
- jScrollPane1.setViewportView(tagNamesList);
+ TagNameScrollPane.setViewportView(tagNamesList);
newTagNameButton.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/images/add-tag.png"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(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);
@@ -100,12 +143,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);
+ }
+ });
+
+ panelDescriptionTextArea.setEditable(false);
+ panelDescriptionTextArea.setBackground(new java.awt.Color(240, 240, 240));
+ panelDescriptionTextArea.setColumns(20);
+ panelDescriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
+ panelDescriptionTextArea.setLineWrap(true);
+ panelDescriptionTextArea.setRows(3);
+ panelDescriptionTextArea.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionTextArea.text")); // NOI18N
+ panelDescriptionTextArea.setWrapStyleWord(true);
+ panelDescriptionTextArea.setFocusable(false);
+ panelDescriptionScrollPane.setViewportView(panelDescriptionTextArea);
+
javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel);
modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout);
modifyTagTypesListPanelLayout.setHorizontalGroup(
@@ -113,40 +181,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(TagNameScrollPane, 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(panelDescriptionScrollPane, 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(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(tagTypesListLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(TagNameScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 338, 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);
@@ -158,27 +284,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,12 +308,15 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
);
}// //GEN-END:initComponents
+ @Messages({"TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.",
+ "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name"})
+
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, TskData.FileKnown.UNKNOWN);
+ 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.
*/
@@ -199,35 +324,66 @@ 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,
- NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"),
- NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"),
+ NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message"),
+ NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title"),
JOptionPane.INFORMATION_MESSAGE);
}
}
}//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);
+ if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) {
+ updatedStatusTags.add(newTagType.getDisplayName());
+ }
+ }
+ }//GEN-LAST:event_editTagNameButtonActionPerformed
+
// Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JScrollPane TagNameScrollPane;
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.JSplitPane jSplitPane1;
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.JScrollPane panelDescriptionScrollPane;
+ private javax.swing.JTextArea panelDescriptionTextArea;
+ private javax.swing.JList tagNamesList;
private javax.swing.JPanel tagTypesAdditionalPanel;
private javax.swing.JLabel tagTypesListLabel;
// End of variables declaration//GEN-END:variables
@@ -237,7 +393,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);
}
}
@@ -247,9 +403,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();
}
/**
@@ -257,19 +413,76 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
*/
@Override
public void store() {
- TagNameDefiniton.setTagNameDefinitions(tagTypes);
+ TagNameDefinition.setTagNameDefinitions(tagTypes);
+ sendStatusChangedEvents();
+ }
+
+ void cancelChanges() {
+ updatedStatusTags.clear();
+ }
+
+ private void sendStatusChangedEvents() {
+ for (String modifiedTagDisplayName : updatedStatusTags) {
+ //if user closes their case after options have been changed but before application of them is complete don't notify
+ if (Case.isCaseOpen()) {
+ Case.getCurrentCase().notifyTagDefinitionChanged(modifiedTagDisplayName);
+ }
+ }
+ updatedStatusTags.clear();
}
/**
* 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().getKnownStatus() == TskData.FileKnown.BAD) {
+ 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 adfcbf0029..f96fe08f23 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
@@ -27,6 +27,7 @@ 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;
@@ -69,6 +70,15 @@ public class TagsManager implements Closeable {
|| tagDisplayName.contains(";"));
}
+ @NbBundle.Messages({"TagsManager.notableTagEnding.text= (Notable)"})
+ /**
+ * Get String of text which is used to label tags as notable to the user.
+ *
+ * @return Bundle message TagsManager.notableTagEnding.text
+ */
+ public static String getNotableTagLabel(){
+ return Bundle.TagsManager_notableTagEnding_text();
+ }
/**
* Gets the set of display names of the currently available tag types. This
@@ -83,7 +93,7 @@ public class TagsManager implements Closeable {
*/
public static Set getTagDisplayNames() throws TskCoreException {
Set tagDisplayNames = new HashSet<>();
- Set customNames = TagNameDefiniton.getTagNameDefinitions();
+ Set customNames = TagNameDefinition.getTagNameDefinitions();
customNames.forEach((tagType) -> {
tagDisplayNames.add(tagType.getDisplayName());
});
@@ -102,8 +112,8 @@ public class TagsManager implements Closeable {
public static List getNotableTagDisplayNames() {
List tagDisplayNames = new ArrayList<>();
- for (TagNameDefiniton tagDef : TagNameDefiniton.getTagNameDefinitions()) {
- if (tagDef.isNotable()) {
+ for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) {
+ if (tagDef.getKnownStatus() == TskData.FileKnown.BAD) {
tagDisplayNames.add(tagDef.getDisplayName());
}
}
@@ -170,8 +180,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()) {
@@ -256,9 +266,9 @@ public class TagsManager implements Closeable {
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown knownStatus) throws TagNameAlreadyExistsException, TskCoreException {
try {
TagName tagName = caseDb.addOrUpdateTagName(displayName, description, color, knownStatus);
- Set customTypes = TagNameDefiniton.getTagNameDefinitions();
- customTypes.add(new TagNameDefiniton(displayName, description, color, knownStatus));
- TagNameDefiniton.setTagNameDefinitions(customTypes);
+ 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/casemodule/services/TagsOptionsPanelController.java b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java
index c27835f83a..fcd2131f90 100755
--- a/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java
+++ b/Core/src/org/sleuthkit/autopsy/casemodule/services/TagsOptionsPanelController.java
@@ -69,6 +69,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController {
*/
@Override
public void cancel() {
+ getPanel().cancelChanges();
}
@Override
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
index 2a7fcf168b..fbc955ca72 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/contentviewer/DataContentViewerOtherCases.java
@@ -177,7 +177,7 @@ public class DataContentViewerOtherCases extends javax.swing.JPanel implements D
}
caseDisplayName = eamCasePartial.getDisplayName();
// query case details
- CorrelationCase eamCase = dbManager.getCaseByUUID(eamCasePartial.getCaseUUID());
+ CorrelationCase eamCase = dbManager.getCase(Case.getCurrentCase());
if (eamCase == null) {
JOptionPane.showConfirmDialog(showCaseDetailsMenuItem,
Bundle.DataContentViewerOtherCases_caseDetailsDialog_noDetails(),
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
index f9c2435472..9560d635c4 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/AbstractSqlEamDb.java
@@ -170,9 +170,10 @@ public abstract class AbstractSqlEamDb implements EamDb {
* Expects the Organization for this case to already exist in the database.
*
* @param eamCase The case to add
+ * @returns New Case class with populated database ID
*/
@Override
- public void newCase(CorrelationCase eamCase) throws EamDbException {
+ public CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
Connection conn = connect();
PreparedStatement preparedStatement = null;
@@ -225,6 +226,9 @@ public abstract class AbstractSqlEamDb implements EamDb {
EamDbUtil.closePreparedStatement(preparedStatement);
EamDbUtil.closeConnection(conn);
}
+
+ // get a new version with the updated ID
+ return getCaseByUUID(eamCase.getCaseUUID());
}
/**
@@ -249,9 +253,14 @@ public abstract class AbstractSqlEamDb implements EamDb {
autopsyCase.getExaminerEmail(),
autopsyCase.getExaminerPhone(),
autopsyCase.getCaseNotes());
- newCase(curCeCase);
- return curCeCase;
+ return newCase(curCeCase);
}
+
+ @Override
+ public CorrelationCase getCase(Case autopsyCase) throws EamDbException {
+ return getCaseByUUID(autopsyCase.getName());
+ }
+
/**
* Updates an existing Case in the database
@@ -432,7 +441,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
* @return The data source
*/
@Override
- public CorrelationDataSource getDataSourceDetails(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
+ public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
Connection conn = connect();
CorrelationDataSource eamDataSourceResult = null;
@@ -450,7 +459,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
eamDataSourceResult = getEamDataSourceFromResultSet(resultSet);
}
} catch (SQLException ex) {
- throw new EamDbException("Error getting case details.", ex); // NON-NLS
+ throw new EamDbException("Error getting data source.", ex); // NON-NLS
} finally {
EamDbUtil.closePreparedStatement(preparedStatement);
EamDbUtil.closeResultSet(resultSet);
@@ -1057,12 +1066,12 @@ public abstract class AbstractSqlEamDb implements EamDb {
// We could improve effiency by keeping a list of all datasources and cases
// in the database, but we don't expect the user to be tagging large numbers
// of items (that didn't have the CE ingest module run on them) at once.
- CorrelationCase correlationCase = getCaseByUUID(eamInstance.getCorrelationCase().getCaseUUID());
- if (null == correlationCase) {
- newCase(eamInstance.getCorrelationCase());
- correlationCase = getCaseByUUID(eamInstance.getCorrelationCase().getCaseUUID());
+ CorrelationCase correlationCaseWithId = getCaseByUUID(eamInstance.getCorrelationCase().getCaseUUID());
+ if (null == correlationCaseWithId) {
+ correlationCaseWithId = newCase(eamInstance.getCorrelationCase());
}
- if (null == getDataSourceDetails(correlationCase, eamInstance.getCorrelationDataSource().getDeviceID())) {
+
+ if (null == getDataSource(correlationCaseWithId, eamInstance.getCorrelationDataSource().getDeviceID())) {
newDataSource(eamInstance.getCorrelationDataSource());
}
eamArtifact.getInstances().get(0).setKnownStatus(knownStatus);
@@ -2146,7 +2155,7 @@ public abstract class AbstractSqlEamDb implements EamDb {
return null;
}
CorrelationAttributeInstance eamArtifactInstance = new CorrelationAttributeInstance(
- new CorrelationCase(resultSet.getString("case_uid"), resultSet.getString("case_name")),
+ new CorrelationCase(resultSet.getInt("case_id"), resultSet.getString("case_uid"), resultSet.getString("case_name")),
new CorrelationDataSource(-1, resultSet.getInt("case_id"), resultSet.getString("device_id"), resultSet.getString("name")),
resultSet.getString("file_path"),
resultSet.getString("comment"),
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationCase.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationCase.java
index 466c73a7ee..79d94837ee 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationCase.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/CorrelationCase.java
@@ -49,16 +49,12 @@ public class CorrelationCase implements Serializable {
*
* @param caseUUID Globally unique identifier
* @param displayName
- */
- public CorrelationCase(String caseUUID, String displayName) {
- this(-1, caseUUID, null, displayName, DATE_FORMAT.format(new Date()), null, null, null, null, null);
- }
-
+ */
CorrelationCase(int ID, String caseUUID, String displayName) {
this(ID, caseUUID, null, displayName, DATE_FORMAT.format(new Date()), null, null, null, null, null);
}
- public CorrelationCase(int ID,
+ CorrelationCase(int ID,
String caseUUID,
EamOrganization org,
String displayName,
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
index b3194e4b7f..c2bb0e0016 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamArtifactUtil.java
@@ -96,10 +96,9 @@ public class EamArtifactUtil {
}
// make an instance for the BB source file
- CorrelationCase correlationCase = EamDb.getInstance().getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
if (null == correlationCase) {
- EamDb.getInstance().newCase(Case.getCurrentCase());
- correlationCase = EamDb.getInstance().getCaseByUUID(Case.getCurrentCase().getName());
+ correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase());
}
CorrelationAttributeInstance eamInstance = new CorrelationAttributeInstance(
correlationCase,
@@ -250,10 +249,9 @@ public class EamArtifactUtil {
try {
CorrelationAttribute.Type filesType = EamDb.getInstance().getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
eamArtifact = new CorrelationAttribute(filesType, af.getMd5Hash());
- CorrelationCase correlationCase = EamDb.getInstance().getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase correlationCase = EamDb.getInstance().getCase(Case.getCurrentCase());
if (null == correlationCase) {
- EamDb.getInstance().newCase(Case.getCurrentCase());
- correlationCase = EamDb.getInstance().getCaseByUUID(Case.getCurrentCase().getName());
+ correlationCase = EamDb.getInstance().newCase(Case.getCurrentCase());
}
CorrelationAttributeInstance cei = new CorrelationAttributeInstance(
correlationCase,
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
index 5f2cdfa816..b9ce4320de 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDb.java
@@ -94,14 +94,6 @@ public interface EamDb {
return EamDbUtil.useCentralRepo()
&& EamDbPlatformEnum.getSelectedPlatform() != EamDbPlatformEnum.DISABLED;
}
-
- /**
- * Placeholder version to use for non-read only databases
- * @return The version that will be stored in the database
- */
- static String getDefaultVersion() {
- return "";
- }
/**
* Add a new name/value pair in the db_info table.
@@ -141,7 +133,7 @@ public interface EamDb {
*
* @param eamCase The case to add
*/
- void newCase(CorrelationCase eamCase) throws EamDbException;
+ CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException;
/**
* Creates new Case in the database from the given case
@@ -149,6 +141,8 @@ public interface EamDb {
* @param autopsyCase The case to add
*/
CorrelationCase newCase(Case autopsyCase) throws EamDbException;
+
+
/**
* Updates an existing Case in the database
@@ -157,6 +151,15 @@ public interface EamDb {
*/
void updateCase(CorrelationCase eamCase) throws EamDbException;
+ /**
+ * Retrieves Central Repo case based on an Autopsy Case
+ *
+ * @param autopsyCase Autopsy case to find corresponding CR case for
+ * @return CR Case
+ * @throws EamDbException
+ */
+ CorrelationCase getCase(Case autopsyCase) throws EamDbException;
+
/**
* Retrieves Case details based on Case UUID
*
@@ -189,7 +192,7 @@ public interface EamDb {
*
* @return The data source
*/
- CorrelationDataSource getDataSourceDetails(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
+ CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException;
/**
* Retrieves data sources that are in DB
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java
index 5d70d6fdac..49f49f9d38 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java
@@ -37,6 +37,7 @@ public class EamDbUtil {
private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName());
private static final String CENTRAL_REPO_NAME = "CentralRepository";
private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo";
+ private static final String DEFAULT_ORG_NAME = "Not Specified";
/**
* Close the prepared statement.
@@ -175,11 +176,51 @@ public class EamDbUtil {
return true;
}
+ /**
+ * Check whether the given org is the default organization.
+ *
+ * @param org
+ * @return true if it is the default org, false otherwise
+ */
+ public static boolean isDefaultOrg(EamOrganization org) {
+ return DEFAULT_ORG_NAME.equals(org.getName());
+ }
+
+ /**
+ * Add the default organization to the database
+ *
+ * @param conn
+ * @return true if successful, false otherwise
+ */
+ static boolean insertDefaultOrganization(Connection conn) {
+ if (null == conn) {
+ return false;
+ }
+
+ PreparedStatement preparedStatement = null;
+ String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?)";
+ try {
+ preparedStatement = conn.prepareStatement(sql);
+ preparedStatement.setString(1, DEFAULT_ORG_NAME);
+ preparedStatement.setString(2, "");
+ preparedStatement.setString(3, "");
+ preparedStatement.setString(4, "");
+ preparedStatement.executeUpdate();
+ } catch (SQLException ex) {
+ LOGGER.log(Level.SEVERE, "Error adding default organization", ex);
+ return false;
+ } finally {
+ EamDbUtil.closePreparedStatement(preparedStatement);
+ }
+
+ return true;
+ }
+
/**
* If the Central Repos use has been enabled.
*
* @return true if the Central Repo may be configured, false if it should
- * not be able to be
+ * not be able to be
*/
public static boolean useCentralRepo() {
return Boolean.parseBoolean(ModuleSettings.getConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY));
@@ -190,7 +231,7 @@ public class EamDbUtil {
* configured.
*
* @param centralRepoCheckBoxIsSelected - true if the central repo can be
- * used
+ * used
*/
public static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected) {
ModuleSettings.setConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY, Boolean.toString(centralRepoCheckBoxIsSelected));
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
index bfb3f04b32..324cc2ac7d 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
@@ -485,7 +485,8 @@ public final class PostgresEamDbSettings {
}
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
- && EamDbUtil.insertSchemaVersion(conn);
+ && EamDbUtil.insertSchemaVersion(conn)
+ && EamDbUtil.insertDefaultOrganization(conn);
EamDbUtil.closeConnection(conn);
return result;
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
index 3e79f5abca..85fda8d4a1 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDb.java
@@ -149,16 +149,14 @@ public class SqliteEamDb extends AbstractSqlEamDb {
*
*/
private void setupConnectionPool() throws EamDbException {
+
+ if (dbSettings.dbFileExists() == false) {
+ throw new EamDbException("Central repository database missing");
+ }
+
connectionPool = new BasicDataSource();
connectionPool.setDriverClassName(dbSettings.getDriver());
-
- StringBuilder connectionURL = new StringBuilder();
- connectionURL.append(dbSettings.getJDBCBaseURI());
- connectionURL.append(dbSettings.getDbDirectory());
- connectionURL.append(File.separator);
- connectionURL.append(dbSettings.getDbName());
-
- connectionPool.setUrl(connectionURL.toString());
+ connectionPool.setUrl(dbSettings.getConnectionURL());
// tweak pool configuration
connectionPool.setInitialSize(50);
@@ -279,10 +277,10 @@ public class SqliteEamDb extends AbstractSqlEamDb {
* @param eamCase The case to add
*/
@Override
- public void newCase(CorrelationCase eamCase) throws EamDbException {
+ public CorrelationCase newCase(CorrelationCase eamCase) throws EamDbException {
try{
acquireExclusiveLock();
- super.newCase(eamCase);
+ return super.newCase(eamCase);
} finally {
releaseExclusiveLock();
}
@@ -359,10 +357,10 @@ public class SqliteEamDb extends AbstractSqlEamDb {
* @return The data source
*/
@Override
- public CorrelationDataSource getDataSourceDetails(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
+ public CorrelationDataSource getDataSource(CorrelationCase correlationCase, String dataSourceDeviceId) throws EamDbException {
try{
acquireSharedLock();
- return super.getDataSourceDetails(correlationCase, dataSourceDeviceId);
+ return super.getDataSource(correlationCase, dataSourceDeviceId);
} finally {
releaseSharedLock();
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
index b4ea1aa8a2..c7a3730e46 100755
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
@@ -434,7 +434,8 @@ public final class SqliteEamDbSettings {
}
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
- && EamDbUtil.insertSchemaVersion(conn);
+ && EamDbUtil.insertSchemaVersion(conn)
+ && EamDbUtil.insertDefaultOrganization(conn);
EamDbUtil.closeConnection(conn);
return result;
}
diff --git a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
index dbe17d6e6d..88cf1ed59e 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/eventlisteners/CaseEventListener.java
@@ -48,6 +48,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag;
+import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException;
@@ -97,7 +98,10 @@ final class CaseEventListener implements PropertyChangeListener {
jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt));
}
break;
-
+ case TAG_DEFINITION_CHANGED: {
+ jobProcessingExecutor.submit(new TagDefinitionChangeTask(evt));
+ }
+ break;
case CURRENT_CASE: {
jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt));
}
@@ -294,6 +298,117 @@ final class CaseEventListener implements PropertyChangeListener {
}
+ private final class TagDefinitionChangeTask implements Runnable {
+
+ private final PropertyChangeEvent event;
+
+ private TagDefinitionChangeTask(PropertyChangeEvent evt) {
+ event = evt;
+ }
+
+ @Override
+ public void run() {
+ if (!EamDb.isEnabled()) {
+ return;
+ }
+ //get the display name of the tag that has had it's definition modified
+ String modifiedTagName = (String) event.getOldValue();
+
+ /*
+ * Set knownBad status for all files/artifacts in the given case
+ * that are tagged with the given tag name.
+ */
+ try {
+ TagName tagName = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(modifiedTagName);
+ //First update the artifacts
+ //Get all BlackboardArtifactTags with this tag name
+ List artifactTags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTagsByTagName(tagName);
+ for (BlackboardArtifactTag bbTag : artifactTags) {
+ //start with assumption that none of the other tags applied to this Correlation Attribute will prevent it's status from being changed
+ boolean hasTagWithConflictingKnownStatus = false;
+ // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
+ // we need to check the status of all other tags on this correlation attribute before changing
+ // the status of the correlation attribute in the central repository
+ if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
+ Content content = bbTag.getContent();
+ // If the content which this Blackboard Artifact Tag is linked to is an AbstractFile with KNOWN status then
+ // it's status in the central reporsitory should not be changed to UNKNOWN
+ if ((content instanceof AbstractFile) && (((AbstractFile) content).getKnown() == TskData.FileKnown.KNOWN)) {
+ continue;
+ }
+ //Get the BlackboardArtifact which this BlackboardArtifactTag has been applied to.
+ BlackboardArtifact bbArtifact = bbTag.getArtifact();
+ TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
+ List tags = tagsManager.getBlackboardArtifactTagsByArtifact(bbArtifact);
+ //get all tags which are on this blackboard artifact
+ for (BlackboardArtifactTag t : tags) {
+ //All instances of the modified tag name will be changed, they can not conflict with each other
+ if (t.getName().equals(tagName)) {
+ continue;
+ }
+ //if any other tags on this artifact are Notable in status then this artifact can not have its status changed
+ if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
+ //a tag with a conflicting status has been found, the status of this correlation attribute can not be modified
+ hasTagWithConflictingKnownStatus = true;
+ break;
+ }
+ }
+ }
+ //if the Correlation Attribute will have no tags with a status which would prevent the current status from being changed
+ if (!hasTagWithConflictingKnownStatus) {
+ //Get the correlation atttributes that correspond to the current BlackboardArtifactTag if their status should be changed
+ //with the initial set of correlation attributes this should be a single correlation attribute
+ List convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true);
+ for (CorrelationAttribute eamArtifact : convertedArtifacts) {
+ EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
+ }
+ }
+ }
+ // Next update the files
+
+ List fileTags = Case.getCurrentCase().getSleuthkitCase().getContentTagsByTagName(tagName);
+ //Get all ContentTags with this tag name
+ for (ContentTag contentTag : fileTags) {
+ //start with assumption that none of the other tags applied to this ContentTag will prevent it's status from being changed
+ boolean hasTagWithConflictingKnownStatus = false;
+ // if the status of the tag has been changed to TskData.FileKnown.UNKNOWN
+ // we need to check the status of all other tags on this file before changing
+ // the status of the file in the central repository
+ if (tagName.getKnownStatus() == TskData.FileKnown.UNKNOWN) {
+ Content content = contentTag.getContent();
+ TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
+ List tags = tagsManager.getContentTagsByContent(content);
+ //get all tags which are on this file
+ for (ContentTag t : tags) {
+ //All instances of the modified tag name will be changed, they can not conflict with each other
+ if (t.getName().equals(tagName)) {
+ continue;
+ }
+ //if any other tags on this file are Notable in status then this file can not have its status changed
+ if (TskData.FileKnown.BAD == t.getName().getKnownStatus()) {
+ //a tag with a conflicting status has been found, the status of this file can not be modified
+ hasTagWithConflictingKnownStatus = true;
+ break;
+ }
+ }
+ }
+ //if the file will have no tags with a status which would prevent the current status from being changed
+ if (!hasTagWithConflictingKnownStatus) {
+ final CorrelationAttribute eamArtifact = EamArtifactUtil.getEamArtifactFromContent(contentTag.getContent(),
+ tagName.getKnownStatus(), "");
+ if (eamArtifact != null) {
+ EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
+ }
+ }
+ }
+ } catch (TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, "Cannot update known status in central repository for tag: " + modifiedTagName, ex); //NON-NLS
+ } catch (EamDbException ex) {
+ LOGGER.log(Level.SEVERE, "Cannot get central repository for tag: " + modifiedTagName, ex); //NON-NLS
+ }
+ } //TAG_STATUS_CHANGED
+ }
+
private final class DataSourceAddedTask implements Runnable {
private final EamDb dbManager;
@@ -315,12 +430,11 @@ final class CaseEventListener implements PropertyChangeListener {
try {
String deviceId = Case.getCurrentCase().getSleuthkitCase().getDataSource(newDataSource.getId()).getDeviceId();
- CorrelationCase correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ CorrelationCase correlationCase = dbManager.getCase(Case.getCurrentCase());
if (null == correlationCase) {
- dbManager.newCase(Case.getCurrentCase());
- correlationCase = dbManager.getCaseByUUID(Case.getCurrentCase().getName());
+ correlationCase = dbManager.newCase(Case.getCurrentCase());
}
- if (null == dbManager.getDataSourceDetails(correlationCase, deviceId)) {
+ if (null == dbManager.getDataSource(correlationCase, deviceId)) {
dbManager.newDataSource(CorrelationDataSource.fromTSKDataSource(correlationCase, newDataSource));
}
} catch (EamDbException ex) {
@@ -350,18 +464,6 @@ final class CaseEventListener implements PropertyChangeListener {
if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
Case curCase = (Case) event.getNewValue();
IngestEventsListener.resetCeModuleInstanceCount();
-
- 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());
if (!EamDb.isEnabled()) {
return;
@@ -370,10 +472,8 @@ final class CaseEventListener implements PropertyChangeListener {
try {
// NOTE: Cannot determine if the opened case is a new case or a reopened case,
// so check for existing name in DB and insert if missing.
- CorrelationCase existingCase = dbManager.getCaseByUUID(curCeCase.getCaseUUID());
-
- if (null == existingCase) {
- dbManager.newCase(curCeCase);
+ if (dbManager.getCase(curCase) == null) {
+ dbManager.newCase(curCase);
}
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to Central Repository database.", ex); //NON-NLS
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/ingestmodule/IngestModule.java b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
index 30d374f133..9e1e36cb8a 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/ingestmodule/IngestModule.java
@@ -201,47 +201,36 @@ class IngestModule implements FileIngestModule {
}
jobId = context.getJobId();
- EamDb dbManager;
+ EamDb centralRepoDb;
try {
- dbManager = EamDb.getInstance();
+ centralRepoDb = EamDb.getInstance();
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error connecting to central repository database.", ex); // NON-NLS
throw new IngestModuleException("Error connecting to central repository database.", ex); // NON-NLS
}
try {
- filesType = dbManager.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
+ filesType = centralRepoDb.getCorrelationTypeById(CorrelationAttribute.FILES_TYPE_ID);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
throw new IngestModuleException("Error getting correlation type FILES in ingest module start up.", ex); // NON-NLS
}
- Case curCase = Case.getCurrentCase();
+ Case autopsyCase = Case.getCurrentCase();
try {
- eamCase = dbManager.getCaseByUUID(curCase.getName());
+ eamCase = centralRepoDb.getCase(autopsyCase);
} catch (EamDbException ex) {
throw new IngestModuleException("Unable to get case from central repository database ", ex);
}
if (eamCase == null) {
// ensure we have this case defined in the EAM DB
- 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());
try {
- dbManager.newCase(curCeCase);
- eamCase = dbManager.getCaseByUUID(curCase.getName());
+ eamCase = centralRepoDb.newCase(autopsyCase);
} catch (EamDbException ex) {
LOGGER.log(Level.SEVERE, "Error creating new case in ingest module start up.", ex); // NON-NLS
throw new IngestModuleException("Error creating new case in ingest module start up.", ex); // NON-NLS
}
}
+
try {
eamDataSource = CorrelationDataSource.fromTSKDataSource(eamCase, context.getDataSource());
} catch (EamDbException ex) {
@@ -255,12 +244,12 @@ class IngestModule implements FileIngestModule {
== 1) {
// ensure we have this data source in the EAM DB
try {
- if (null == dbManager.getDataSourceDetails(eamCase, eamDataSource.getDeviceID())) {
- dbManager.newDataSource(eamDataSource);
+ if (null == centralRepoDb.getDataSource(eamCase, eamDataSource.getDeviceID())) {
+ centralRepoDb.newDataSource(eamDataSource);
}
} catch (EamDbException ex) {
- LOGGER.log(Level.SEVERE, "Error creating new data source in ingest module start up.", ex); // NON-NLS
- throw new IngestModuleException("Error creating new data source in ingest module start up.", ex); // NON-NLS
+ LOGGER.log(Level.SEVERE, "Error adding data source to Central Repository.", ex); // NON-NLS
+ throw new IngestModuleException("Error adding data source to Central Repository.", ex); // NON-NLS
}
}
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/ManageOrganizationsDialog.java b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java
index ad6c26e4d8..9055485e2f 100644
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageOrganizationsDialog.java
@@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages;
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.EamDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -72,7 +73,7 @@ public final class ManageOrganizationsDialog extends JDialog {
organizationList.setModel(rulesListModel);
organizationList.addListSelectionListener(new OrganizationListSelectionListener());
populateList();
- setButtonsEnabled(organizationList.getSelectedValue() != null);
+ setButtonsEnabled(organizationList.getSelectedValue());
newOrg = null;
} catch (EamDbException ex) {
Exceptions.printStackTrace(ex);
@@ -421,9 +422,15 @@ public final class ManageOrganizationsDialog extends JDialog {
return newOrg;
}
- private void setButtonsEnabled(boolean isSelected) {
- editButton.setEnabled(isSelected);
- deleteButton.setEnabled(isSelected);
+ private void setButtonsEnabled(EamOrganization selectedOrg) {
+ boolean isSelected = (selectedOrg != null);
+ boolean isDefaultOrg = false;
+ if(selectedOrg != null){
+ isDefaultOrg = EamDbUtil.isDefaultOrg(selectedOrg);
+ }
+
+ editButton.setEnabled(isSelected && (! isDefaultOrg));
+ deleteButton.setEnabled(isSelected && (! isDefaultOrg));
}
/**
@@ -436,9 +443,8 @@ public final class ManageOrganizationsDialog extends JDialog {
if (e.getValueIsAdjusting()) {
return;
}
- EamOrganization selected = organizationList.getSelectedValue();
- boolean isSelected = (selected != null);
- setButtonsEnabled(isSelected);
+ EamOrganization selected = organizationList.getSelectedValue();
+ setButtonsEnabled(selected);
if (selected != null) {
orgNameTextField.setText(selected.getName());
pocNameTextField.setText(selected.getPocName());
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 ff179c3032..0000000000
--- a/Core/src/org/sleuthkit/autopsy/centralrepository/optionspanel/ManageTagsDialog.java
+++ /dev/null
@@ -1,364 +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 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 = TagsManager.getNotableTagDisplayNames();
-
- List tagNames = new ArrayList<>();
- try {
- tagNames.addAll(TagsManager.getTagDisplayNames());
- } 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.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/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
index 06607d7d9b..00881c2ca7 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.form
@@ -22,12 +22,15 @@
-
+
+
+
+
-
+
@@ -47,246 +50,475 @@
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
-
-
-
-
-
-
+
+
+
+
+
+
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
index 4f95087f66..a62ae4400c 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/AutopsyOptionsPanel.java
@@ -18,28 +18,259 @@
*/
package org.sleuthkit.autopsy.corecomponents;
+import java.awt.image.BufferedImage;
import java.io.File;
+import java.io.IOException;
+import java.lang.management.ManagementFactory;
+import java.nio.charset.Charset;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Optional;
+import java.util.StringJoiner;
+import java.util.logging.Level;
+import javax.imageio.ImageIO;
+import javax.swing.ImageIcon;
import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
import org.netbeans.spi.options.OptionsPanelController;
+import org.openide.util.NbBundle;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.openide.util.NbBundle.Messages;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
+import org.sleuthkit.autopsy.coreutils.PlatformUtil;
+import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.report.ReportBranding;
/**
* Options panel that allow users to set application preferences.
*/
+@Messages({"AutopsyOptionsPanel.agencyLogoPreview.text=No logo
selected
",
+ "AutopsyOptionsPanel.logoPanel.border.title=Logo",
+ "AutopsyOptionsPanel.viewPanel.border.title=View",
+ "AutopsyOptionsPanel.invalidImageFile.msg=The selected file was not able to be used as an agency logo.",
+ "AutopsyOptionsPanel.invalidImageFile.title=Invalid Image File",
+ "AutopsyOptionsPanel.restartNecessaryWarning.text=A restart is necessary for any changes to max memory to take effect.",
+ "AutopsyOptionsPanel.totalMemoryLabel.text=Total System Memory:",
+ "AutopsyOptionsPanel.maxMemoryLabel.text=Maximum JVM Memory:",
+ "AutopsyOptionsPanel.maxMemoryUnitsLabel.text=GB",
+ "AutopsyOptionsPanel.runtimePanel.border.title=Runtime",
+ "AutopsyOptionsPanel.invalidReasonLabel.not64BitInstall.text=JVM memory settings only enabled for 64 bit version",
+ "AutopsyOptionsPanel.invalidReasonLabel.noValueEntered.text=No value entered",
+ "AutopsyOptionsPanel.invalidReasonLabel.invalidCharacters.text=Invalid characters, value must be a positive integer",
+ "# {0} - minimumMemory",
+ "AutopsyOptionsPanel.invalidReasonLabel.underMinMemory.text=Value must be at least {0}GB",
+ "# {0} - systemMemory",
+ "AutopsyOptionsPanel.invalidReasonLabel.overMaxMemory.text=Value must be less than the total system memory of {0}GB",
+ "AutopsyOptionsPanel.invalidReasonLabel.developerMode.text=Memory settings are not available while running in developer mode"})
+
final class AutopsyOptionsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final JFileChooser fc;
+ private static final String ETC_FOLDER_NAME = "etc";
+ private static final String CONFIG_FILE_EXTENSION = ".conf";
+ private static final long ONE_BILLION = 1000000000L; //used to roughly convert system memory from bytes to gigabytes
+ private static final long MEGA_IN_GIGA = 1024; //used to convert memory settings saved as megabytes to gigabytes
+ private static final int MIN_MEMORY_IN_GB = 2; //the enforced minimum memory in gigabytes
+ private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
+ private String initialMemValue = Long.toString(Runtime.getRuntime().maxMemory() / ONE_BILLION);
AutopsyOptionsPanel() {
initComponents();
fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false);
+ fc.setAcceptAllFileFilterUsed(false);
fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
+ if (!PlatformUtil.is64BitJVM() || Version.getBuildType() == Version.Type.DEVELOPMENT) {
+ //32 bit JVM has a max heap size of 1.4 gb to 4 gb depending on OS
+ //So disabling the setting of heap size when the JVM is not 64 bit
+ //Is the safest course of action
+ //And the file won't exist in the install folder when running through netbeans
+ memField.setEnabled(false);
+ }
+ systemMemoryTotal.setText(Long.toString(getSystemMemoryInGB()));
+ }
+
+ /**
+ * Get the total system memory in gigabytes which exists on the machine
+ * which the application is running.
+ *
+ * @return the total system memory
+ */
+ private long getSystemMemoryInGB() {
+ long memorySize = ((com.sun.management.OperatingSystemMXBean) ManagementFactory
+ .getOperatingSystemMXBean()).getTotalPhysicalMemorySize();
+ return memorySize / ONE_BILLION;
+ }
+
+ /**
+ * Gets the currently saved max java heap space in gigabytes.
+ *
+ * @return @throws IOException when unable to get a valid setting
+ */
+ private long getCurrentJvmMaxMemoryInGB() throws IOException {
+ String currentXmx = getCurrentXmxValue();
+ char units = '-';
+ Long value = 0L;
+ if (currentXmx.length() > 1) {
+ units = currentXmx.charAt(currentXmx.length() - 1);
+ value = Long.parseLong(currentXmx.substring(0, currentXmx.length() - 1));
+ } else {
+ throw new IOException("No memory setting found in String: " + currentXmx);
+ }
+ //some older .conf files might have the units as megabytes instead of gigabytes
+ switch (units) {
+ case 'g':
+ case 'G':
+ return value;
+ case 'm':
+ case 'M':
+ return value / MEGA_IN_GIGA;
+ default:
+ throw new IOException("Units were not recognized as parsed: " + units);
+ }
+ }
+
+ /*
+ * The value currently saved in the conf file as the max java heap space
+ * available to this application. Form will be an integer followed by a
+ * character indicating units. Helper method for
+ * getCurrentJvmMaxMemoryInGB()
+ *
+ * @return the saved value for the max java heap space
+ *
+ * @throws IOException if the conf file does not exist in either the user
+ * directory or the install directory
+ */
+ private String getCurrentXmxValue() throws IOException {
+ String[] settings;
+ String currentSetting = "";
+ File userConfFile = getUserFolderConfFile();
+ if (!userConfFile.exists()) {
+ settings = getDefaultsFromFileContents(readConfFile(getInstallFolderConfFile()));
+ } else {
+ settings = getDefaultsFromFileContents(readConfFile(userConfFile));
+ }
+ for (String option : settings) {
+ if (option.startsWith("-J-Xmx")) {
+ currentSetting = option.replace("-J-Xmx", "").trim();
+ }
+ }
+ return currentSetting;
+ }
+
+ /**
+ * Get the conf file from the install directory which stores the default
+ * values for the settings.
+ *
+ * @return the file which has the applications default .conf file
+ *
+ * @throws IOException when the file does not exist.
+ */
+ private static File getInstallFolderConfFile() throws IOException {
+ String confFileName = Version.getName() + CONFIG_FILE_EXTENSION;
+ String installFolder = PlatformUtil.getInstallPath();
+ File installFolderEtc = new File(installFolder, ETC_FOLDER_NAME);
+ File installFolderConfigFile = new File(installFolderEtc, confFileName);
+ if (!installFolderConfigFile.exists()) {
+ throw new IOException("Conf file could not be found" + installFolderConfigFile.toString());
+ }
+ return installFolderConfigFile;
+ }
+
+ /**
+ * Get the conf file from the directory which stores the currently in use
+ * settings. Creates the directory for the file if the directory does not
+ * exist.
+ *
+ * @return the file which has the applications current .conf file
+ */
+ private static File getUserFolderConfFile() {
+ String confFileName = Version.getName() + CONFIG_FILE_EXTENSION;
+ File userFolder = PlatformUtil.getUserDirectory();
+ File userEtcFolder = new File(userFolder, ETC_FOLDER_NAME);
+ if (!userEtcFolder.exists()) {
+ userEtcFolder.mkdir();
+ }
+ return new File(userEtcFolder, confFileName);
+ }
+
+ /**
+ * Take the conf file in the install directory and save a copy of it to the
+ * user directory. The copy will be modified to include the current memory
+ * setting.
+ *
+ * @throws IOException when unable to write a conf file or access the
+ * install folders conf file
+ */
+ private void writeEtcConfFile() throws IOException {
+ StringBuilder content = new StringBuilder();
+ List confFile = readConfFile(getInstallFolderConfFile());
+ for (String line : confFile) {
+ if (line.contains("-J-Xmx")) {
+ String[] splitLine = line.split(" ");
+ StringJoiner modifiedLine = new StringJoiner(" ");
+ for (String piece : splitLine) {
+ if (piece.contains("-J-Xmx")) {
+ piece = "-J-Xmx" + memField.getText() + "g";
+ }
+ modifiedLine.add(piece);
+ }
+ content.append(modifiedLine.toString());
+ } else {
+ content.append(line);
+ }
+ content.append("\n");
+ }
+ Files.write(getUserFolderConfFile().toPath(), content.toString().getBytes());
+ }
+
+ /**
+ * Reads a conf file line by line putting each line into a list of strings
+ * which will be returned.
+ *
+ * @param configFile the .conf file which you wish to read.
+ *
+ * @return a list of strings with a string for each line in the conf file
+ * specified.
+ */
+ private static List readConfFile(File configFile) {
+ List lines = new ArrayList<>();
+ if (null != configFile) {
+ Path filePath = configFile.toPath();
+ Charset charset = Charset.forName("UTF-8");
+ try {
+ lines = Files.readAllLines(filePath, charset);
+ } catch (IOException e) {
+ logger.log(Level.SEVERE, "Error reading config file contents. {}", configFile.getAbsolutePath());
+ }
+ }
+ return lines;
+ }
+
+ /**
+ * Find the string in the list of strings which contains the default options
+ * settings and split it into an array of strings containing one element for
+ * each setting specified.
+ *
+ * @param list a list of string representing lines of a .conf file
+ *
+ * @return an array of strings for each argument on the line which has the
+ * default options, returns an empty array of Strings if default
+ * options is not present.
+ */
+ private static String[] getDefaultsFromFileContents(List list) {
+ Optional defaultSettings = list.stream().filter(line -> line.startsWith("default_options=")).findFirst();
+
+ if (defaultSettings.isPresent()) {
+ return defaultSettings.get().replace("default_options=", "").replaceAll("\"", "").split(" ");
+ }
+ return new String[]{};
}
void load() {
@@ -53,7 +284,41 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.setSelected(!useLocalTime);
- agencyLogoPathField.setText(ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP));
+ String path = ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP);
+ try {
+ updateAgencyLogo(path);
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex);
+ }
+ if (memField.isEnabled()) {
+ try {
+ initialMemValue = Long.toString(getCurrentJvmMaxMemoryInGB());
+ } catch (IOException ex) {
+ logger.log(Level.SEVERE, "Can't read current Jvm max memory setting from file", ex);
+ memField.setEnabled(false);
+ }
+ memField.setText(initialMemValue);
+ }
+ isMemFieldValid(); //ensure the error message is up to date
+ }
+
+ private void updateAgencyLogo(String path) throws IOException {
+ agencyLogoPathField.setText(path);
+ ImageIcon agencyLogoIcon = new ImageIcon();
+ agencyLogoPreview.setText(Bundle.AutopsyOptionsPanel_agencyLogoPreview_text());
+ if (!agencyLogoPathField.getText().isEmpty()) {
+ File file = new File(agencyLogoPathField.getText());
+ if (file.exists()) {
+ BufferedImage image = ImageIO.read(file); //create it as an image first to support BMP files
+ if (image == null) {
+ throw new IOException("Unable to read file as a BufferedImage for file " + file.toString());
+ }
+ agencyLogoIcon = new ImageIcon(image.getScaledInstance(64, 64, 4));
+ agencyLogoPreview.setText("");
+ }
+ }
+ agencyLogoPreview.setIcon(agencyLogoIcon);
+ agencyLogoPreview.repaint();
}
void store() {
@@ -64,15 +329,22 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
if (!agencyLogoPathField.getText().isEmpty()) {
- File image = new File(agencyLogoPathField.getText());
- if (image.exists()) {
+ File file = new File(agencyLogoPathField.getText());
+ if (file.exists()) {
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
}
}
+ if (memField.isEnabled()) { //if the field could of been changed we need to try and save it
+ try {
+ writeEtcConfFile();
+ } catch (IOException ex) {
+ logger.log(Level.WARNING, "Unable to save config file to " + PlatformUtil.getUserDirectory() + "\\" + ETC_FOLDER_NAME, ex);
+ }
+ }
}
boolean valid() {
- return true;
+ return isMemFieldValid();
}
/**
@@ -87,24 +359,96 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
buttonGroup3 = new javax.swing.ButtonGroup();
jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel();
- useBestViewerRB = new javax.swing.JRadioButton();
- keepCurrentViewerRB = new javax.swing.JRadioButton();
- jLabelSelectFile = new javax.swing.JLabel();
- jLabelTimeDisplay = new javax.swing.JLabel();
- useLocalTimeRB = new javax.swing.JRadioButton();
- useGMTTimeRB = new javax.swing.JRadioButton();
- jLabelHideKnownFiles = new javax.swing.JLabel();
- dataSourcesHideKnownCB = new javax.swing.JCheckBox();
- viewsHideKnownCB = new javax.swing.JCheckBox();
- dataSourcesHideSlackCB = new javax.swing.JCheckBox();
- viewsHideSlackCB = new javax.swing.JCheckBox();
- jLabelHideSlackFiles = new javax.swing.JLabel();
+ logoPanel = new javax.swing.JPanel();
agencyLogoImageLabel = new javax.swing.JLabel();
agencyLogoPathField = new javax.swing.JTextField();
browseLogosButton = new javax.swing.JButton();
+ agencyLogoPreview = new javax.swing.JLabel();
+ viewPanel = new javax.swing.JPanel();
+ jLabelSelectFile = new javax.swing.JLabel();
+ useBestViewerRB = new javax.swing.JRadioButton();
+ keepCurrentViewerRB = new javax.swing.JRadioButton();
+ jLabelHideKnownFiles = new javax.swing.JLabel();
+ dataSourcesHideKnownCB = new javax.swing.JCheckBox();
+ viewsHideKnownCB = new javax.swing.JCheckBox();
+ jLabelHideSlackFiles = new javax.swing.JLabel();
+ dataSourcesHideSlackCB = new javax.swing.JCheckBox();
+ viewsHideSlackCB = new javax.swing.JCheckBox();
+ jLabelTimeDisplay = new javax.swing.JLabel();
+ useLocalTimeRB = new javax.swing.JRadioButton();
+ useGMTTimeRB = new javax.swing.JRadioButton();
+ runtimePanel = new javax.swing.JPanel();
+ maxMemoryLabel = new javax.swing.JLabel();
+ maxMemoryUnitsLabel = new javax.swing.JLabel();
+ totalMemoryLabel = new javax.swing.JLabel();
+ systemMemoryTotal = new javax.swing.JLabel();
+ restartNecessaryWarning = new javax.swing.JLabel();
+ memField = new javax.swing.JTextField();
+ invalidReasonLabel = new javax.swing.JLabel();
+ maxMemoryUnitsLabel1 = new javax.swing.JLabel();
jScrollPane1.setBorder(null);
+ logoPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.logoPanel.border.title"))); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
+
+ agencyLogoPathField.setEditable(false);
+ agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
+ agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
+ agencyLogoPathField.setFocusable(false);
+ agencyLogoPathField.setRequestFocusEnabled(false);
+
+ org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
+ browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ browseLogosButtonActionPerformed(evt);
+ }
+ });
+
+ agencyLogoPreview.setHorizontalAlignment(javax.swing.SwingConstants.CENTER);
+ org.openide.awt.Mnemonics.setLocalizedText(agencyLogoPreview, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPreview.text")); // NOI18N
+ agencyLogoPreview.setBorder(javax.swing.BorderFactory.createEtchedBorder());
+ agencyLogoPreview.setMaximumSize(new java.awt.Dimension(64, 64));
+ agencyLogoPreview.setMinimumSize(new java.awt.Dimension(64, 64));
+ agencyLogoPreview.setPreferredSize(new java.awt.Dimension(64, 64));
+
+ javax.swing.GroupLayout logoPanelLayout = new javax.swing.GroupLayout(logoPanel);
+ logoPanel.setLayout(logoPanelLayout);
+ logoPanelLayout.setHorizontalGroup(
+ logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, logoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(agencyLogoImageLabel)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(browseLogosButton)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(agencyLogoPreview, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ logoPanelLayout.setVerticalGroup(
+ logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(agencyLogoPreview, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGroup(logoPanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(agencyLogoImageLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(logoPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(agencyLogoPathField)
+ .addComponent(browseLogosButton))))
+ .addGap(0, 0, 0))
+ );
+
+ viewPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewPanel.border.title"))); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N
+
buttonGroup1.add(useBestViewerRB);
org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.text")); // NOI18N
useBestViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.toolTipText")); // NOI18N
@@ -123,7 +467,37 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}
});
- org.openide.awt.Mnemonics.setLocalizedText(jLabelSelectFile, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelSelectFile.text")); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N
+ dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ dataSourcesHideKnownCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N
+ viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ viewsHideKnownCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
+ dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ dataSourcesHideSlackCBActionPerformed(evt);
+ }
+ });
+
+ org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
+ viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
+ public void actionPerformed(java.awt.event.ActionEvent evt) {
+ viewsHideSlackCBActionPerformed(evt);
+ }
+ });
org.openide.awt.Mnemonics.setLocalizedText(jLabelTimeDisplay, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelTimeDisplay.text")); // NOI18N
@@ -143,93 +517,41 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}
});
- org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N
-
- org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N
- dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- dataSourcesHideKnownCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(viewsHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideKnownCB.text")); // NOI18N
- viewsHideKnownCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- viewsHideKnownCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideSlackCB.text")); // NOI18N
- dataSourcesHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- dataSourcesHideSlackCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(viewsHideSlackCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.viewsHideSlackCB.text")); // NOI18N
- viewsHideSlackCB.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- viewsHideSlackCBActionPerformed(evt);
- }
- });
-
- org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
-
- org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
-
- agencyLogoPathField.setEditable(false);
- agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
- agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
- agencyLogoPathField.setFocusable(false);
- agencyLogoPathField.setRequestFocusEnabled(false);
-
- org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
- browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
- public void actionPerformed(java.awt.event.ActionEvent evt) {
- browseLogosButtonActionPerformed(evt);
- }
- });
-
- javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
- jPanel1.setLayout(jPanel1Layout);
- jPanel1Layout.setHorizontalGroup(
- jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
+ javax.swing.GroupLayout viewPanelLayout = new javax.swing.GroupLayout(viewPanel);
+ viewPanel.setLayout(viewPanelLayout);
+ viewPanelLayout.setHorizontalGroup(
+ viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabelTimeDisplay)
- .addComponent(jLabelHideKnownFiles)
- .addComponent(jLabelSelectFile)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(useLocalTimeRB)
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(viewPanelLayout.createSequentialGroup()
+ .addGap(10, 10, 10)
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(viewPanelLayout.createSequentialGroup()
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useGMTTimeRB)
.addComponent(keepCurrentViewerRB)
.addComponent(useBestViewerRB)
.addComponent(dataSourcesHideKnownCB)
- .addComponent(viewsHideKnownCB))))
- .addContainerGap(140, Short.MAX_VALUE))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabelHideSlackFiles)
- .addComponent(agencyLogoImageLabel)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGap(10, 10, 10)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(browseLogosButton))
+ .addComponent(viewsHideKnownCB))
+ .addGap(0, 0, Short.MAX_VALUE))
+ .addGroup(viewPanelLayout.createSequentialGroup()
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(dataSourcesHideSlackCB)
- .addComponent(viewsHideSlackCB))))
- .addGap(0, 0, Short.MAX_VALUE))))
+ .addComponent(viewsHideSlackCB)
+ .addComponent(useLocalTimeRB))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
+ .addGroup(viewPanelLayout.createSequentialGroup()
+ .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabelHideSlackFiles)
+ .addComponent(jLabelTimeDisplay)
+ .addComponent(jLabelHideKnownFiles)
+ .addComponent(jLabelSelectFile))
+ .addGap(30, 30, 30))))
);
- jPanel1Layout.setVerticalGroup(
- jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
+ viewPanelLayout.setVerticalGroup(
+ viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap()
.addComponent(jLabelSelectFile)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@@ -253,14 +575,97 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(useGMTTimeRB)
+ .addComponent(useGMTTimeRB))
+ );
+
+ runtimePanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.runtimePanel.border.title"))); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(maxMemoryLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryUnitsLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(totalMemoryLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.totalMemoryLabel.text")); // NOI18N
+
+ systemMemoryTotal.setHorizontalAlignment(javax.swing.SwingConstants.TRAILING);
+
+ restartNecessaryWarning.setIcon(new javax.swing.ImageIcon(getClass().getResource("/org/sleuthkit/autopsy/corecomponents/warning16.png"))); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(restartNecessaryWarning, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.restartNecessaryWarning.text")); // NOI18N
+
+ memField.setHorizontalAlignment(javax.swing.JTextField.TRAILING);
+ memField.addKeyListener(new java.awt.event.KeyAdapter() {
+ public void keyReleased(java.awt.event.KeyEvent evt) {
+ memFieldKeyReleased(evt);
+ }
+ });
+
+ invalidReasonLabel.setForeground(new java.awt.Color(255, 0, 0));
+
+ org.openide.awt.Mnemonics.setLocalizedText(maxMemoryUnitsLabel1, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.maxMemoryUnitsLabel.text")); // NOI18N
+
+ javax.swing.GroupLayout runtimePanelLayout = new javax.swing.GroupLayout(runtimePanel);
+ runtimePanel.setLayout(runtimePanelLayout);
+ runtimePanelLayout.setHorizontalGroup(
+ runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(runtimePanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(maxMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 114, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(totalMemoryLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 0, Short.MAX_VALUE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(memField, javax.swing.GroupLayout.DEFAULT_SIZE, 37, Short.MAX_VALUE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(agencyLogoImageLabel)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(maxMemoryUnitsLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 17, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(18, 18, 18)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(restartNecessaryWarning, javax.swing.GroupLayout.DEFAULT_SIZE, 417, Short.MAX_VALUE)
+ .addComponent(invalidReasonLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ );
+ runtimePanelLayout.setVerticalGroup(
+ runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(runtimePanelLayout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(maxMemoryUnitsLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(memField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(invalidReasonLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(maxMemoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
+ .addGroup(runtimePanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(restartNecessaryWarning, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(maxMemoryUnitsLabel1, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(totalMemoryLabel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(systemMemoryTotal, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)))
+ );
+
+ javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
+ jPanel1.setLayout(jPanel1Layout);
+ jPanel1Layout.setHorizontalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(logoPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(runtimePanel, javax.swing.GroupLayout.Alignment.TRAILING, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addContainerGap())
+ );
+ jPanel1Layout.setVerticalGroup(
+ jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGap(0, 0, 0)
+ .addComponent(viewPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(agencyLogoPathField)
- .addComponent(browseLogosButton))
- .addGap(35, 35, 35))
+ .addComponent(runtimePanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addGap(0, 0, 0))
);
jScrollPane1.setViewportView(jPanel1);
@@ -269,11 +674,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
this.setLayout(layout);
layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(jScrollPane1)
+ .addGap(0, 0, 0))
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jScrollPane1)
+ .addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
);
}// //GEN-END:initComponents
@@ -310,22 +717,84 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
+ String oldLogoPath = agencyLogoPathField.getText();
int returnState = fc.showOpenDialog(this);
if (returnState == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath();
- agencyLogoPathField.setText(path);
- firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
+ try {
+ updateAgencyLogo(path);
+ firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
+ } catch (IOException | IndexOutOfBoundsException ex) {
+ JOptionPane.showMessageDialog(null,
+ NbBundle.getMessage(this.getClass(),
+ "AutopsyOptionsPanel.invalidImageFile.msg"),
+ NbBundle.getMessage(this.getClass(), "AutopsyOptionsPanel.invalidImageFile.title"),
+ JOptionPane.ERROR_MESSAGE);
+ try {
+ updateAgencyLogo(oldLogoPath); //restore previous setting if new one is invalid
+ } catch (IOException ex1) {
+ logger.log(Level.WARNING, "Error loading image from previously saved agency logo path", ex1);
+ }
+ }
}
}//GEN-LAST:event_browseLogosButtonActionPerformed
+ private void memFieldKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_memFieldKeyReleased
+ String memText = memField.getText();
+ if (memText.equals(initialMemValue)) {
+ //if it is still the initial value don't fire change
+ return;
+ }
+ firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
+ }//GEN-LAST:event_memFieldKeyReleased
+
+ /**
+ * Checks that if the mem field is enabled it has a valid value.
+ *
+ * @return true if the memfield is valid false if it is not
+ */
+ private boolean isMemFieldValid() {
+ String memText = memField.getText();
+ invalidReasonLabel.setText("");
+ if (!PlatformUtil.is64BitJVM()) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_not64BitInstall_text());
+ //the panel should be valid when it is a 32 bit jvm because the memfield will be disabled.
+ return true;
+ }
+ if (Version.getBuildType() == Version.Type.DEVELOPMENT) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_developerMode_text());
+ //the panel should be valid when you are running in developer mode because the memfield will be disabled
+ return true;
+ }
+ if (memText.length() == 0) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_noValueEntered_text());
+ return false;
+ }
+ if (memText.replaceAll("[^\\d]", "").length() != memText.length()) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_invalidCharacters_text());
+ return false;
+ }
+ int parsedInt = Integer.parseInt(memText);
+ if (parsedInt < MIN_MEMORY_IN_GB) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_underMinMemory_text(MIN_MEMORY_IN_GB));
+ return false;
+ }
+ if (parsedInt >= getSystemMemoryInGB()) {
+ invalidReasonLabel.setText(Bundle.AutopsyOptionsPanel_invalidReasonLabel_overMaxMemory_text(getSystemMemoryInGB()));
+ return false;
+ }
+ return true;
+ }
// Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel agencyLogoImageLabel;
private javax.swing.JTextField agencyLogoPathField;
+ private javax.swing.JLabel agencyLogoPreview;
private javax.swing.JButton browseLogosButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.ButtonGroup buttonGroup3;
private javax.swing.JCheckBox dataSourcesHideKnownCB;
private javax.swing.JCheckBox dataSourcesHideSlackCB;
+ private javax.swing.JLabel invalidReasonLabel;
private javax.swing.JLabel jLabelHideKnownFiles;
private javax.swing.JLabel jLabelHideSlackFiles;
private javax.swing.JLabel jLabelSelectFile;
@@ -333,10 +802,21 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRB;
+ private javax.swing.JPanel logoPanel;
+ private javax.swing.JLabel maxMemoryLabel;
+ private javax.swing.JLabel maxMemoryUnitsLabel;
+ private javax.swing.JLabel maxMemoryUnitsLabel1;
+ private javax.swing.JTextField memField;
+ private javax.swing.JLabel restartNecessaryWarning;
+ private javax.swing.JPanel runtimePanel;
+ private javax.swing.JLabel systemMemoryTotal;
+ private javax.swing.JLabel totalMemoryLabel;
private javax.swing.JRadioButton useBestViewerRB;
private javax.swing.JRadioButton useGMTTimeRB;
private javax.swing.JRadioButton useLocalTimeRB;
+ private javax.swing.JPanel viewPanel;
private javax.swing.JCheckBox viewsHideKnownCB;
private javax.swing.JCheckBox viewsHideSlackCB;
// End of variables declaration//GEN-END:variables
+
}
diff --git a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
index 5ac6cbd626..26a2cc03e0 100755
--- a/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/corecomponents/Bundle.properties
@@ -1,7 +1,7 @@
CTL_DataContentAction=DataContent
CTL_DataContentTopComponent=Data Content
CTL_CustomAboutAction=About
-OptionsCategory_Name_General=View
+OptionsCategory_Name_General=Application
OptionsCategory_Keywords_General=Autopsy Options
HINT_DataContentTopComponent=This is a DataContent window
HINT_NodeTableTopComponent=This is a DataResult window
@@ -198,7 +198,6 @@ AutopsyOptionsPanel.agencyLogoPathField.text=
SortChooserDialog.label=remove
SortChooser.addCriteriaButton.text=Add Sort Criteria
DataResultViewerThumbnail.sortButton.text=Sort
-
CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n
CriterionChooser.removeButton.text=Remove
CriterionChooser.descendingRadio.text=\u25bc Descending
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/tags/Category.java b/Core/src/org/sleuthkit/autopsy/datamodel/DhsImageCategory.java
similarity index 85%
rename from Core/src/org/sleuthkit/autopsy/datamodel/tags/Category.java
rename to Core/src/org/sleuthkit/autopsy/datamodel/DhsImageCategory.java
index 39d624110f..2357c61599 100644
--- a/Core/src/org/sleuthkit/autopsy/datamodel/tags/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.datamodel.tags;
+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/datamodel/FileTypeExtensions.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
index 4195b33008..eafa8377b2 100755
--- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypeExtensions.java
@@ -38,6 +38,7 @@ public class FileTypeExtensions {
private final static List WEB_EXTENSIONS = Arrays.asList(".html", ".htm", ".css", ".js", ".php", ".aspx"); //NON-NLS
private final static List PDF_EXTENSIONS = Arrays.asList(".pdf"); //NON-NLS
private final static List ARCHIVE_EXTENSIONS = Arrays.asList(".zip", ".rar", ".7zip", ".7z", ".arj", ".tar", ".gzip", ".bzip", ".bzip2", ".cab", ".jar", ".cpio", ".ar", ".gz", ".tgz", ".bz2"); //NON-NLS
+ private final static List DATABASE_EXTENSIONS = Arrays.asList(".db", ".db3", ".sqlite", ".sqlite3"); //NON-NLS
public static List getImageExtensions() {
return IMAGE_EXTENSIONS;
@@ -75,6 +76,10 @@ public class FileTypeExtensions {
return ARCHIVE_EXTENSIONS;
}
+ public static List getDatabaseExtensions() {
+ return DATABASE_EXTENSIONS;
+ }
+
private FileTypeExtensions() {
}
diff --git a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
index 305da8e953..2341fff12c 100755
--- a/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
+++ b/Core/src/org/sleuthkit/autopsy/datamodel/FileTypesByExtension.java
@@ -34,6 +34,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.UserPreferences;
@@ -423,6 +424,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
}
// root node filters
+ @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
@@ -437,10 +439,13 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
FileTypeExtensions.getArchiveExtensions()),
- TSK_DOCUMENT_FILTER(3, "TSK_DOCUMENT_FILTER", //NON-NLS
+ TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS
+ NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"),
+ FileTypeExtensions.getDatabaseExtensions()),
+ TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
- TSK_EXECUTABLE_FILTER(3, "TSK_EXECUTABLE_FILTER", //NON-NLS
+ TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
FileTypeExtensions.getExecutableExtensions()); //NON-NLS
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
index f23dd57f84..d240310b1c 100755
--- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle.properties
@@ -20,8 +20,7 @@ IngestMessagePanel.totalUniqueMessagesNameVal.text=-
IngestJob.progress.dataSourceIngest.initialDisplayName=Analyzing {0}
IngestJob.progress.dataSourceIngest.displayName={0} for {1}
IngestJob.progress.fileIngest.displayName=Analyzing files from {0}
-IngestJob.progress.fileIngest.cancelMessage=Waiting for {0} on {1}
-IngestJob.progress.cancelling={0} (Cancelling...)
+IngestJob.progress.cancelling=Cancelling...
IngestJob.cancellationDialog.title=Cancel Ingest
IngestDialog.startButton.title=Start
IngestDialog.closeButton.title=Close
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties
index f7af8964cc..2fc82d0dd9 100755
--- a/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties
+++ b/Core/src/org/sleuthkit/autopsy/ingest/Bundle_ja.properties
@@ -2,7 +2,7 @@ CTL_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8
HINT_IngestMessageTopComponent=\u30e1\u30c3\u30bb\u30fc\u30b8\u30a6\u30a3\u30f3\u30c9\u30a6
IngestDialog.closeButton.title=\u9589\u3058\u308b
IngestDialog.startButton.title=\u958b\u59cb
-IngestJob.progress.cancelling={0}\uff08\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026\uff09
+IngestJob.progress.cancelling=\u30ad\u30e3\u30f3\u30bb\u30eb\u4e2d\u2026
IngestJob.progress.dataSourceIngest.displayName={1}\u306e{0}
IngestJob.progress.fileIngest.displayName={0}\u306e\u30d5\u30a1\u30a4\u30eb\u3092\u89e3\u6790\u4e2d
IngestManager.moduleErr=\u30e2\u30b8\u30e5\u30fc\u30eb\u30a8\u30e9\u30fc
@@ -90,7 +90,6 @@ IngestProgressSnapshotPanel.SnapshotsTableModel.colNames.jobID=\u30b8\u30e7\u30d
ModuleTableModel.colName.module=\u30e2\u30b8\u30e5\u30fc\u30eb
Menu/Tools/RunIngestModules=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30e2\u30b8\u30e5\u30fc\u30eb\u3092\u5b9f\u884c
-IngestJob.progress.fileIngest.cancelMessage={1}\u306e{0}\u3092\u5f85\u3063\u3066\u3044\u307e\u3059
IngestManager.OpenEventChannel.Fail.ErrMsg=\u3053\u306e\u30b1\u30fc\u30b9\u3067\u4f7f\u308f\u308c\u3066\u3044\u308b\u304b\u3082\u3057\u308c\u306a\u3044\u4ed6\u306e\u30ce\u30fc\u30c9\u306b\u89e3\u6790\u30d7\u30ed\u30bb\u30b9\u304c\u63a5\u7d9a\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
IngestManager.OpenEventChannel.Fail.Title=\u63a5\u7d9a\u5931\u6557
IngestJobSettings.moduleSettingsSave.warning={1}\u30b3\u30f3\u30c6\u30ad\u30b9\u30c8\u306e{0}\u30e2\u30b8\u30e5\u30fc\u30eb\u7528\u306e\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30b8\u30e7\u30d6\u8a2d\u5b9a\u3092\u8aad\u307f\u8fbc\u307f\u4e2d\u306b\u30a8\u30e9\u30fc\u304c\u767a\u751f\u3057\u307e\u3057\u305f\u3002
diff --git a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java
index f9caad7683..b8d5b7e359 100755
--- a/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java
+++ b/Core/src/org/sleuthkit/autopsy/ingest/DataSourceIngestJob.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2016 Basis Technology Corp.
+ * Copyright 2014-2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -125,10 +125,9 @@ final class DataSourceIngestJob {
* class.
*/
private volatile boolean currentDataSourceIngestModuleCancelled;
+ private final List cancelledDataSourceIngestModules = new CopyOnWriteArrayList<>();
private volatile boolean cancelled;
private volatile IngestJob.CancellationReason cancellationReason = IngestJob.CancellationReason.NOT_CANCELLED;
- private final Object cancellationStateMonitor = new Object();
- private final List cancelledDataSourceIngestModules = new CopyOnWriteArrayList<>();
/**
* A data source ingest job uses the task scheduler singleton to create and
@@ -989,66 +988,25 @@ final class DataSourceIngestJob {
* @param reason The cancellation reason.
*/
void cancel(IngestJob.CancellationReason reason) {
- if (this.doUI) {
- /**
- * Put a cancellation message on data source level ingest progress
- * bar, if it is still running.
- */
- synchronized (this.dataSourceIngestProgressLock) {
- if (dataSourceIngestProgress != null) {
- final String displayName = NbBundle.getMessage(this.getClass(),
- "IngestJob.progress.dataSourceIngest.initialDisplayName",
- dataSource.getName());
- dataSourceIngestProgress.setDisplayName(
- NbBundle.getMessage(this.getClass(),
- "IngestJob.progress.cancelling",
- displayName));
- }
- }
-
- /**
- * Put a cancellation message on the file level ingest progress bar,
- * if it is still running.
- */
- synchronized (this.fileIngestProgressLock) {
- if (this.fileIngestProgress != null) {
- final String displayName = NbBundle.getMessage(this.getClass(),
- "IngestJob.progress.fileIngest.displayName",
- this.dataSource.getName());
- this.fileIngestProgress.setDisplayName(
- NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling",
- displayName));
- if (!this.currentFileIngestModule.isEmpty() && !this.currentFileIngestTask.isEmpty()) {
- this.fileIngestProgress.progress(NbBundle.getMessage(this.getClass(),
- "IngestJob.progress.fileIngest.cancelMessage",
- this.currentFileIngestModule, this.currentFileIngestTask));
- }
-
- }
- }
- }
-
- /*
- * If the work is not already done, show this job as cancelled for the
- * given reason.
- */
- if (Stages.FINALIZATION != stage) {
- synchronized (cancellationStateMonitor) {
- /*
- * These fields are volatile for reading, synchronized on the
- * monitor here for writing.
- */
- this.cancelled = true;
- this.cancellationReason = reason;
- }
- }
-
- /**
- * Tell the task scheduler to cancel all pending tasks, i.e., tasks not
- * not being performed by an ingest thread.
- */
+ this.cancelled = true;
+ this.cancellationReason = reason;
DataSourceIngestJob.taskScheduler.cancelPendingTasksForIngestJob(this);
- this.checkForStageCompleted();
+
+ if (this.doUI) {
+ synchronized (this.dataSourceIngestProgressLock) {
+ if (null != dataSourceIngestProgress) {
+ dataSourceIngestProgress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestJob.progress.dataSourceIngest.initialDisplayName", dataSource.getName()));
+ dataSourceIngestProgress.progress(NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling"));
+ }
+ }
+
+ synchronized (this.fileIngestProgressLock) {
+ if (null != this.fileIngestProgress) {
+ this.fileIngestProgress.setDisplayName(NbBundle.getMessage(this.getClass(), "IngestJob.progress.fileIngest.displayName", this.dataSource.getName()));
+ this.fileIngestProgress.progress(NbBundle.getMessage(this.getClass(), "IngestJob.progress.cancelling"));
+ }
+ }
+ }
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java
index 7d4328da59..7a9d9b04ef 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/EmbeddedFileExtractorIngestModule.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2013-2017 Basis Technology Corp.
+ * Copyright 2015 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -44,7 +44,7 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS
private String moduleDirRelative;
private String moduleDirAbsolute;
- private ImageExtractor imageExtractor;
+ private MSOfficeEmbeddedContentExtractor officeExtractor;
private SevenZipExtractor archiveExtractor;
private FileTypeDetector fileTypeDetector;
@@ -98,10 +98,10 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
}
/*
- * Construct an embedded images extractor for processing Microsoft
+ * Construct an embedded content extractor for processing Microsoft
* Office documents.
*/
- this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute);
+ this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute);
}
@Override
@@ -134,8 +134,8 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
*/
if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) {
archiveExtractor.unpack(abstractFile);
- } else if (imageExtractor.isImageExtractionSupported(abstractFile)) {
- imageExtractor.extractImage(abstractFile);
+ } else if (officeExtractor.isContentExtractionSupported(abstractFile)) {
+ officeExtractor.extractEmbeddedContent(abstractFile);
}
return ProcessResult.OK;
}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java
similarity index 58%
rename from Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java
rename to Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java
index d58d935e97..61376d31f1 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/ImageExtractor.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/embeddedfileextractor/MSOfficeEmbeddedContentExtractor.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2017 Basis Technology Corp.
+ * Copyright 2015 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -21,14 +21,16 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
-import java.lang.IllegalArgumentException;
-import java.lang.IndexOutOfBoundsException;
-import java.lang.NullPointerException;
+import java.io.InputStream;
import java.nio.file.Paths;
import java.util.ArrayList;
+import java.util.HashMap;
import java.util.List;
+import java.util.Map;
import java.util.logging.Level;
-import org.apache.poi.POIXMLException;
+import org.apache.commons.io.FileUtils;
+import org.apache.commons.io.FilenameUtils;
+import org.apache.commons.io.IOUtils;
import org.apache.poi.hwpf.usermodel.Picture;
import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
@@ -39,11 +41,18 @@ import org.apache.poi.hwpf.model.PicturesTable;
import org.apache.poi.sl.usermodel.PictureData.PictureType;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.RecordFormatException;
-import org.apache.poi.xslf.usermodel.XMLSlideShow;
-import org.apache.poi.xslf.usermodel.XSLFPictureData;
-import org.apache.poi.xssf.usermodel.XSSFWorkbook;
-import org.apache.poi.xwpf.usermodel.XWPFDocument;
-import org.apache.poi.xwpf.usermodel.XWPFPictureData;
+import org.apache.tika.config.TikaConfig;
+import org.apache.tika.detect.Detector;
+import org.apache.tika.exception.TikaException;
+import org.apache.tika.extractor.EmbeddedDocumentExtractor;
+import org.apache.tika.extractor.ParsingEmbeddedDocumentExtractor;
+import org.apache.tika.metadata.Metadata;
+import org.apache.tika.mime.MediaType;
+import org.apache.tika.mime.MimeTypeException;
+import org.apache.tika.parser.AutoDetectParser;
+import org.apache.tika.parser.ParseContext;
+import org.apache.tika.parser.Parser;
+import org.apache.tika.sax.BodyContentHandler;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager;
@@ -57,24 +66,34 @@ import org.sleuthkit.datamodel.EncodedFileOutputStream;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
+import org.xml.sax.ContentHandler;
+import org.xml.sax.SAXException;
-class ImageExtractor {
+/**
+ * Extracts embedded content (e.g. images, audio, video) from Microsoft Office
+ * documents (both original and OOXML forms).
+ */
+class MSOfficeEmbeddedContentExtractor {
private final FileManager fileManager;
private final IngestServices services;
- private static final Logger logger = Logger.getLogger(ImageExtractor.class.getName());
+ private static final Logger LOGGER = Logger.getLogger(MSOfficeEmbeddedContentExtractor.class.getName());
private final IngestJobContext context;
private String parentFileName;
- private final String UNKNOWN_NAME_PREFIX = "image_"; //NON-NLS
+ private final String UNKNOWN_IMAGE_NAME_PREFIX = "image_"; //NON-NLS
private final FileTypeDetector fileTypeDetector;
private String moduleDirRelative;
private String moduleDirAbsolute;
+ private AutoDetectParser parser = new AutoDetectParser();
+ private Detector detector = parser.getDetector();
+ private TikaConfig config = TikaConfig.getDefaultConfig();
+
/**
- * Enum of mimetypes which support image extraction
+ * Enum of mimetypes for which we can extract embedded content.
*/
- enum SupportedImageExtractionFormats {
+ enum SupportedExtractionFormats {
DOC("application/msword"), //NON-NLS
DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS
@@ -85,7 +104,7 @@ class ImageExtractor {
private final String mimeType;
- SupportedImageExtractionFormats(final String mimeType) {
+ SupportedExtractionFormats(final String mimeType) {
this.mimeType = mimeType;
}
@@ -93,11 +112,10 @@ class ImageExtractor {
public String toString() {
return this.mimeType;
}
- // TODO Expand to support more formats
}
- private SupportedImageExtractionFormats abstractFileExtractionFormat;
+ private SupportedExtractionFormats abstractFileExtractionFormat;
- ImageExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) {
+ MSOfficeEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) {
this.fileManager = Case.getCurrentCase().getServices().getFileManager();
this.services = IngestServices.getInstance();
@@ -111,15 +129,15 @@ class ImageExtractor {
* This method returns true if the file format is currently supported. Else
* it returns false. Performs only Apache Tika based detection.
*
- * @param abstractFile The AbstractFilw whose mimetype is to be determined.
+ * @param abstractFile The AbstractFile whose mimetype is to be determined.
*
* @return This method returns true if the file format is currently
* supported. Else it returns false.
*/
- boolean isImageExtractionSupported(AbstractFile abstractFile) {
+ boolean isContentExtractionSupported(AbstractFile abstractFile) {
try {
String abstractFileMimeType = fileTypeDetector.getFileType(abstractFile);
- for (SupportedImageExtractionFormats s : SupportedImageExtractionFormats.values()) {
+ for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) {
if (s.toString().equals(abstractFileMimeType)) {
abstractFileExtractionFormat = s;
return true;
@@ -127,60 +145,55 @@ class ImageExtractor {
}
return false;
} catch (TskCoreException ex) {
- logger.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
+ LOGGER.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
return false;
}
}
/**
- * This method selects the appropriate process of extracting images from
- * files using POI classes. Once the images have been extracted, the method
- * adds them to the DB and fires a ModuleContentEvent. ModuleContent Event
- * is not fired if the no images were extracted from the processed file.
+ * This method selects the appropriate process of extracting embedded
+ * content from files using either Tika or POI classes. Once the content has
+ * been extracted as files, the method adds them to the DB and fires a
+ * ModuleContentEvent. ModuleContent Event is not fired if no content
+ * was extracted from the processed file.
*
- * @param format
* @param abstractFile The abstract file to be processed.
*/
- void extractImage(AbstractFile abstractFile) {
- //
- // switchcase for different supported formats
- // process abstractFile according to the format by calling appropriate methods.
-
- List listOfExtractedImages = null;
+ void extractEmbeddedContent(AbstractFile abstractFile) {
+ List listOfExtractedImages = null;
List listOfExtractedImageAbstractFiles = null;
this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile);
- //check if already has derived files, skip
+
+ // Skip files that already have been unpacked.
try {
if (abstractFile.hasChildren()) {
//check if local unpacked dir exists
if (new File(getOutputFolderPath(parentFileName)).exists()) {
- logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS
+ LOGGER.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS
return;
}
}
} catch (TskCoreException e) {
- logger.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
+ LOGGER.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
return;
}
+
+ // Call the appropriate extraction method based on mime type
switch (abstractFileExtractionFormat) {
- case DOC:
- listOfExtractedImages = extractImagesFromDoc(abstractFile);
- break;
case DOCX:
- listOfExtractedImages = extractImagesFromDocx(abstractFile);
+ case PPTX:
+ case XLSX:
+ listOfExtractedImages = extractEmbeddedContentFromOOXML(abstractFile);
+ break;
+ case DOC:
+ listOfExtractedImages = extractEmbeddedImagesFromDoc(abstractFile);
break;
case PPT:
- listOfExtractedImages = extractImagesFromPpt(abstractFile);
- break;
- case PPTX:
- listOfExtractedImages = extractImagesFromPptx(abstractFile);
+ listOfExtractedImages = extractEmbeddedImagesFromPpt(abstractFile);
break;
case XLS:
listOfExtractedImages = extractImagesFromXls(abstractFile);
break;
- case XLSX:
- listOfExtractedImages = extractImagesFromXlsx(abstractFile);
- break;
default:
break;
}
@@ -190,13 +203,13 @@ class ImageExtractor {
}
// the common task of adding abstractFile to derivedfiles is performed.
listOfExtractedImageAbstractFiles = new ArrayList<>();
- for (ExtractedImage extractedImage : listOfExtractedImages) {
+ for (ExtractedFile extractedImage : listOfExtractedImages) {
try {
listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(),
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
} catch (TskCoreException ex) {
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
+ LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
}
}
if (!listOfExtractedImages.isEmpty()) {
@@ -206,43 +219,79 @@ class ImageExtractor {
}
/**
- * Extract images from doc format files.
+ * Extracts embedded content from OOXML documents (i.e. pptx, docx and xlsx)
+ * using Tika. This will extract images and other multimedia content
+ * embedded in the given file.
+ *
+ * @param abstractFile The file to extract content from.
+ *
+ * @return A list of extracted files.
+ */
+ private List extractEmbeddedContentFromOOXML(AbstractFile abstractFile) {
+ Metadata metadata = new Metadata();
+
+ ParseContext parseContext = new ParseContext();
+ parseContext.set(Parser.class, parser);
+
+ // Passing -1 to the BodyContentHandler constructor disables the Tika
+ // write limit (which defaults to 100,000 characters.
+ ContentHandler contentHandler = new BodyContentHandler(-1);
+
+ // TODO: this will be needed once we upgrade to Tika 1.16 or later.
+ // OfficeParserConfig officeParserConfig = new OfficeParserConfig();
+ // officeParserConfig.setUseSAXPptxExtractor(true);
+ // officeParserConfig.setUseSAXDocxExtractor(true);
+ // parseContext.set(OfficeParserConfig.class, officeParserConfig);
+ EmbeddedDocumentExtractor extractor = new EmbeddedContentExtractor(parseContext);
+ parseContext.set(EmbeddedDocumentExtractor.class, extractor);
+ ReadContentInputStream stream = new ReadContentInputStream(abstractFile);
+
+ try {
+ parser.parse(stream, contentHandler, metadata, parseContext);
+ } catch (IOException | SAXException | TikaException ex) {
+ LOGGER.log(Level.WARNING, "Error while parsing file, skipping: " + abstractFile.getName(), ex); //NON-NLS
+ return null;
+ }
+
+ return ((EmbeddedContentExtractor) extractor).getExtractedImages();
+ }
+
+ /**
+ * Extract embedded images from doc format files.
*
* @param af the file from which images are to be extracted.
*
* @return list of extracted images. Returns null in case no images were
* extracted.
*/
- private List extractImagesFromDoc(AbstractFile af) {
+ private List extractEmbeddedImagesFromDoc(AbstractFile af) {
List listOfAllPictures;
-
+
try {
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
PicturesTable pictureTable = doc.getPicturesTable();
listOfAllPictures = pictureTable.getAllPictures();
- } catch (IOException | IllegalArgumentException |
- IndexOutOfBoundsException | NullPointerException ex) {
+ } catch (IOException | IllegalArgumentException
+ | IndexOutOfBoundsException | NullPointerException ex) {
// IOException:
// Thrown when the document has issues being read.
-
+
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document's format is Word 95 or older. Alternatively, this is
// thrown when attempting to load an RTF file as a DOC file.
// However, our code verifies the file format before ever running it
- // through the ImageExtractor. This exception gets thrown in the
+ // through the EmbeddedContentExtractor. This exception gets thrown in the
// "IN10-0137.E01" image regardless. The reason is unknown.
-
// IndexOutOfBoundsException:
// NullPointerException:
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
-
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
+ LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@@ -255,7 +304,7 @@ class ImageExtractor {
if (outputFolderPath == null) {
return null;
}
- List listOfExtractedImages = new ArrayList<>();
+ List listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (Picture picture : listOfAllPictures) {
String fileName = picture.suggestFullFileName();
@@ -266,99 +315,43 @@ class ImageExtractor {
}
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
// TODO Extract more info from the Picture viz ctime, crtime, atime, mtime
- listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), picture.getSize(), af));
+ listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize()));
}
return listOfExtractedImages;
}
/**
- * Extract images from docx format files.
+ * Extract embedded images from ppt format files.
*
* @param af the file from which images are to be extracted.
*
* @return list of extracted images. Returns null in case no images were
* extracted.
*/
- private List extractImagesFromDocx(AbstractFile af) {
- List listOfAllPictures = null;
-
- try {
- XWPFDocument docx = new XWPFDocument(new ReadContentInputStream(af));
- listOfAllPictures = docx.getAllPictures();
- } catch (POIXMLException | IOException ex) {
- // POIXMLException:
- // Thrown when document fails to load
-
- // IOException:
- // Thrown when the document has issues being read.
-
- return null;
- } catch (Throwable ex) {
- // instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS
- return null;
- }
-
- // if no images are extracted from the PPT, return null, else initialize
- // the output folder for image extraction.
- String outputFolderPath;
- if (listOfAllPictures.isEmpty()) {
- return null;
- } else {
- outputFolderPath = getOutputFolderPath(this.parentFileName);
- }
- if (outputFolderPath == null) {
- return null;
- }
- List listOfExtractedImages = new ArrayList<>();
- byte[] data = null;
- for (XWPFPictureData xwpfPicture : listOfAllPictures) {
- String fileName = xwpfPicture.getFileName();
- try {
- data = xwpfPicture.getData();
- } catch (Exception ex) {
- return null;
- }
- writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
- listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), xwpfPicture.getData().length, af));
- }
- return listOfExtractedImages;
- }
-
- /**
- * Extract images from ppt format files.
- *
- * @param af the file from which images are to be extracted.
- *
- * @return list of extracted images. Returns null in case no images were
- * extracted.
- */
- private List extractImagesFromPpt(AbstractFile af) {
+ private List extractEmbeddedImagesFromPpt(AbstractFile af) {
List listOfAllPictures = null;
-
+
try {
HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
listOfAllPictures = ppt.getPictureData();
- } catch (IOException | IllegalArgumentException |
- IndexOutOfBoundsException ex) {
+ } catch (IOException | IllegalArgumentException
+ | IndexOutOfBoundsException ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
// also get thrown for unknown reasons.
-
+
// IOException:
// Thrown when the document has issues being read.
-
// IndexOutOfBoundsException:
// This gets thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
-
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
+ LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@@ -374,10 +367,10 @@ class ImageExtractor {
return null;
}
- // extract the images to the above initialized outputFolder.
+ // extract the content to the above initialized outputFolder.
// extraction path - outputFolder/image_number.ext
int i = 0;
- List listOfExtractedImages = new ArrayList<>();
+ List listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (HSLFPictureData pictureData : listOfAllPictures) {
@@ -404,80 +397,19 @@ class ImageExtractor {
default:
continue;
}
- String imageName = UNKNOWN_NAME_PREFIX + i + ext; //NON-NLS
+ String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + ext; //NON-NLS
try {
data = pictureData.getData();
} catch (Exception ex) {
return null;
}
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
- listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af));
+ listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
i++;
}
return listOfExtractedImages;
}
- /**
- * Extract images from pptx format files.
- *
- * @param af the file from which images are to be extracted.
- *
- * @return list of extracted images. Returns null in case no images were
- * extracted.
- */
- private List extractImagesFromPptx(AbstractFile af) {
- List listOfAllPictures = null;
-
- try {
- XMLSlideShow pptx = new XMLSlideShow(new ReadContentInputStream(af));
- listOfAllPictures = pptx.getPictureData();
- } catch (POIXMLException | IOException ex) {
- // POIXMLException:
- // Thrown when document fails to load.
-
- // IOException:
- // Thrown when the document has issues being read
-
- return null;
- } catch (Throwable ex) {
- // instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS
- return null;
- }
-
- // if no images are extracted from the PPT, return null, else initialize
- // the output folder for image extraction.
- String outputFolderPath;
- if (listOfAllPictures.isEmpty()) {
- return null;
- } else {
- outputFolderPath = getOutputFolderPath(this.parentFileName);
- }
- if (outputFolderPath == null) {
- return null;
- }
-
- List listOfExtractedImages = new ArrayList<>();
- byte[] data = null;
- for (XSLFPictureData xslsPicture : listOfAllPictures) {
-
- // get image file name, write it to the module outputFolder, and add
- // it to the listOfExtractedImageAbstractFiles.
- String fileName = xslsPicture.getFileName();
- try {
- data = xslsPicture.getData();
- } catch (Exception ex) {
- return null;
- }
- writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
- listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), xslsPicture.getData().length, af));
-
- }
-
- return listOfExtractedImages;
-
- }
-
/**
* Extract images from xls format files.
*
@@ -486,41 +418,37 @@ class ImageExtractor {
* @return list of extracted images. Returns null in case no images were
* extracted.
*/
- private List extractImagesFromXls(AbstractFile af) {
+ private List extractImagesFromXls(AbstractFile af) {
List extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
-
+
try {
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
listOfAllPictures = xls.getAllPictures();
- } catch (IOException | LeftoverDataException |
- RecordFormatException | IllegalArgumentException |
- IndexOutOfBoundsException ex) {
+ } catch (IOException | LeftoverDataException
+ | RecordFormatException | IllegalArgumentException
+ | IndexOutOfBoundsException ex) {
// IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may
// also get thrown for unknown reasons.
-
+
// IOException:
// Thrown when the document has issues being read.
-
// LeftoverDataException:
// This is thrown for poorly formatted files that have more data
// than expected.
-
// RecordFormatException:
// This is thrown for poorly formatted files that have less data
// that expected.
-
// IllegalArgumentException:
// IndexOutOfBoundsException:
// These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly
// handling.
-
return null;
} catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
+ LOGGER.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
return null;
}
@@ -537,75 +465,17 @@ class ImageExtractor {
}
int i = 0;
- List listOfExtractedImages = new ArrayList<>();
+ List listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
- String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
+ String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
try {
data = pictureData.getData();
} catch (Exception ex) {
return null;
}
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
- listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af));
- i++;
- }
- return listOfExtractedImages;
-
- }
-
- /**
- * Extract images from xlsx format files.
- *
- * @param af the file from which images are to be extracted.
- *
- * @return list of extracted images. Returns null in case no images were
- * extracted.
- */
- private List extractImagesFromXlsx(AbstractFile af) {
- List extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
-
- try {
- Workbook xlsx = new XSSFWorkbook(new ReadContentInputStream(af));
- listOfAllPictures = xlsx.getAllPictures();
- } catch (POIXMLException | IOException ex) {
- // POIXMLException:
- // Thrown when document fails to load.
-
- // IOException:
- // Thrown when the document has issues being read
-
- return null;
- } catch (Throwable ex) {
- // instantiating POI containers throw RuntimeExceptions
- logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS
- return null;
- }
-
- // if no images are extracted from the PPT, return null, else initialize
- // the output folder for image extraction.
- String outputFolderPath;
- if (listOfAllPictures.isEmpty()) {
- return null;
- } else {
- outputFolderPath = getOutputFolderPath(this.parentFileName);
- }
- if (outputFolderPath == null) {
- return null;
- }
-
- int i = 0;
- List listOfExtractedImages = new ArrayList<>();
- byte[] data = null;
- for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
- String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension();
- try {
- data = pictureData.getData();
- } catch (Exception ex) {
- return null;
- }
- writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
- listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af));
+ listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
i++;
}
return listOfExtractedImages;
@@ -623,18 +493,17 @@ class ImageExtractor {
try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) {
fos.write(data);
} catch (IOException ex) {
- logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS
+ LOGGER.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS
}
}
/**
- * Gets path to the output folder for image extraction. If the path does not
+ * Gets path to the output folder for file extraction. If the path does not
* exist, it is created.
*
- * @param parentFileName name of the abstract file being processed for image
- * extraction.
+ * @param parentFileName name of the abstract file being processed
*
- * @return path to the image extraction folder for a given abstract file.
+ * @return path to the file extraction folder for a given abstract file.
*/
private String getOutputFolderPath(String parentFileName) {
String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName;
@@ -643,7 +512,7 @@ class ImageExtractor {
try {
outputFilePath.mkdirs();
} catch (SecurityException ex) {
- logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex);
+ LOGGER.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex);
return null;
}
}
@@ -665,11 +534,11 @@ class ImageExtractor {
}
/**
- * Represents the image extracted using POI methods. Currently, POI is not
- * capable of extracting ctime, crtime, mtime, and atime; these values are
- * set to 0.
+ * Represents a file extracted using either Tika or POI methods. Currently,
+ * POI is not capable of extracting ctime, crtime, mtime, and atime; these
+ * values are set to 0.
*/
- private static class ExtractedImage {
+ private static class ExtractedFile {
//String fileName, String localPath, long size, long ctime, long crtime,
//long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails
@@ -680,13 +549,12 @@ class ImageExtractor {
private final long crtime;
private final long atime;
private final long mtime;
- private final AbstractFile parentFile;
- ExtractedImage(String fileName, String localPath, long size, AbstractFile parentFile) {
- this(fileName, localPath, size, 0, 0, 0, 0, parentFile);
+ ExtractedFile(String fileName, String localPath, long size) {
+ this(fileName, localPath, size, 0, 0, 0, 0);
}
- ExtractedImage(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, AbstractFile parentFile) {
+ ExtractedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime) {
this.fileName = fileName;
this.localPath = localPath;
this.size = size;
@@ -694,7 +562,6 @@ class ImageExtractor {
this.crtime = crtime;
this.atime = atime;
this.mtime = mtime;
- this.parentFile = parentFile;
}
public String getFileName() {
@@ -724,9 +591,84 @@ class ImageExtractor {
public long getMtime() {
return mtime;
}
+ }
- public AbstractFile getParentFile() {
- return parentFile;
+ /**
+ * Our custom embedded content extractor for OOXML files. We pass an
+ * instance of this class to Tika and Tika calls the parseEmbedded() method
+ * when it encounters an embedded file.
+ */
+ private class EmbeddedContentExtractor extends ParsingEmbeddedDocumentExtractor {
+
+ private int fileCount = 0;
+ // Map of file name to ExtractedFile instance. This can revert to a
+ // plain old list after we upgrade to Tika 1.16 or above.
+ private final Map nameToExtractedFileMap = new HashMap<>();
+
+ public EmbeddedContentExtractor(ParseContext context) {
+ super(context);
+ }
+
+ @Override
+ public boolean shouldParseEmbedded(Metadata metadata) {
+ return true;
+ }
+
+ @Override
+ public void parseEmbedded(InputStream stream, ContentHandler handler,
+ Metadata metadata, boolean outputHtml) throws SAXException, IOException {
+
+ // Get the mime type for the embedded document
+ MediaType contentType = detector.detect(stream, metadata);
+
+ if (!contentType.getType().equalsIgnoreCase("image") //NON-NLS
+ && !contentType.getType().equalsIgnoreCase("video") //NON-NLS
+ && !contentType.getType().equalsIgnoreCase("application") //NON-NLS
+ && !contentType.getType().equalsIgnoreCase("audio")) { //NON-NLS
+ return;
+ }
+
+ // try to get the name of the embedded file from the metadata
+ String name = metadata.get(Metadata.RESOURCE_NAME_KEY);
+
+ // TODO: This can be removed after we upgrade to Tika 1.16 or
+ // above. The 1.16 version of Tika keeps track of files that
+ // have been seen before.
+ if (nameToExtractedFileMap.containsKey(name)) {
+ return;
+ }
+
+ if (name == null) {
+ name = UNKNOWN_IMAGE_NAME_PREFIX + fileCount++;
+ } else {
+ //make sure to select only the file name (not any directory paths
+ //that might be included in the name) and make sure
+ //to normalize the name
+ name = FilenameUtils.normalize(FilenameUtils.getName(name));
+ }
+
+ // Get the suggested extension based on mime type.
+ if (name.indexOf('.') == -1) {
+ try {
+ name += config.getMimeRepository().forName(contentType.toString()).getExtension();
+ } catch (MimeTypeException ex) {
+ LOGGER.log(Level.WARNING, "Failed to get suggested extension for the following type: " + contentType.toString(), ex); //NON-NLS
+ }
+ }
+
+ File extractedFile = new File(Paths.get(getOutputFolderPath(parentFileName), name).toString());
+ byte[] fileData = IOUtils.toByteArray(stream);
+ writeExtractedImage(extractedFile.getAbsolutePath(), fileData);
+ nameToExtractedFileMap.put(name, new ExtractedFile(name, getFileRelativePath(name), fileData.length));
+ }
+
+ /**
+ * Get list of extracted files.
+ *
+ * @return List of extracted files.
+ */
+ public List getExtractedImages() {
+ return new ArrayList<>(nameToExtractedFileMap.values());
}
}
}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties
new file mode 100755
index 0000000000..fdc7d9ed0d
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties
@@ -0,0 +1,8 @@
+EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text=Minimum Entropy:
+EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text=Minimum File Size:
+EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text=Consider only files with sizes that are multiples of 512.
+EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text=Consider slack space files.
+EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text=
+EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text=
+EncryptionDetectionIngestJobSettingsPanel.mbLabel.text=MB
+EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text=Detection Settings
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
new file mode 100755
index 0000000000..15fccb6a74
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionFileIngestModule.java
@@ -0,0 +1,280 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 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.encryptiondetection;
+
+import java.io.BufferedInputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.nio.file.Paths;
+import java.util.Collections;
+import java.util.logging.Level;
+import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.services.Blackboard;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.autopsy.ingest.FileIngestModuleAdapter;
+import org.sleuthkit.autopsy.ingest.IngestJobContext;
+import org.sleuthkit.autopsy.ingest.IngestMessage;
+import org.sleuthkit.autopsy.ingest.IngestModule;
+import org.sleuthkit.autopsy.ingest.IngestServices;
+import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
+import org.sleuthkit.autopsy.modules.filetypeid.FileTypeDetector;
+import org.sleuthkit.datamodel.AbstractFile;
+import org.sleuthkit.datamodel.BlackboardArtifact;
+import org.sleuthkit.datamodel.ReadContentInputStream;
+import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
+
+/**
+ * File ingest module to detect encryption.
+ */
+final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
+
+ static final double DEFAULT_CONFIG_MINIMUM_ENTROPY = 7.5;
+ static final int DEFAULT_CONFIG_MINIMUM_FILE_SIZE = 5242880; // 5MB;
+ static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED = true;
+ static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED = true;
+
+ private static final int FILE_SIZE_MODULUS = 512;
+ private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2))
+ private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
+
+ private final IngestServices SERVICES = IngestServices.getInstance();
+ private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName());
+ private FileTypeDetector fileTypeDetector;
+ private Blackboard blackboard;
+ private double calculatedEntropy;
+
+ private final double minimumEntropy;
+ private final int minimumFileSize;
+ private final boolean fileSizeMultipleEnforced;
+ private final boolean slackFilesAllowed;
+
+ /**
+ * Create a EncryptionDetectionFileIngestModule object that will detect
+ * files that are encrypted and create blackboard artifacts as appropriate.
+ * The supplied EncryptionDetectionIngestJobSettings object is used to
+ * configure the module.
+ */
+ EncryptionDetectionFileIngestModule(EncryptionDetectionIngestJobSettings settings) {
+ minimumEntropy = settings.getMinimumEntropy();
+ minimumFileSize = settings.getMinimumFileSize();
+ fileSizeMultipleEnforced = settings.isFileSizeMultipleEnforced();
+ slackFilesAllowed = settings.isSlackFilesAllowed();
+ }
+
+ @Override
+ public void startUp(IngestJobContext context) throws IngestModule.IngestModuleException {
+ blackboard = Case.getCurrentCase().getServices().getBlackboard();
+ try {
+ fileTypeDetector = new FileTypeDetector();
+ } catch (FileTypeDetector.FileTypeDetectorInitException ex) {
+ throw new IngestModule.IngestModuleException("Failed to create file type detector", ex);
+ }
+ }
+
+ @Override
+ public IngestModule.ProcessResult process(AbstractFile file) {
+
+ try {
+ if (isFileEncrypted(file)) {
+ return flagFile(file);
+ }
+ } catch (IOException | TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, String.format("Unable to process file '%s'", Paths.get(file.getParentPath(), file.getName())), ex);
+ return IngestModule.ProcessResult.ERROR;
+ }
+
+ return IngestModule.ProcessResult.OK;
+ }
+
+ /**
+ * Create a blackboard artifact.
+ *
+ * @param The file to be processed.
+ *
+ * @return 'OK' if the file was processed successfully, or 'ERROR' if there
+ * was a problem.
+ */
+ private IngestModule.ProcessResult flagFile(AbstractFile file) {
+ try {
+ BlackboardArtifact artifact = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED);
+
+ try {
+ /*
+ * Index the artifact for keyword search.
+ */
+ blackboard.indexArtifact(artifact);
+ } catch (Blackboard.BlackboardException ex) {
+ LOGGER.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex); //NON-NLS
+ }
+
+ /*
+ * Send an event to update the view with the new result.
+ */
+ SERVICES.fireModuleDataEvent(new ModuleDataEvent(EncryptionDetectionModuleFactory.getModuleName(), BlackboardArtifact.ARTIFACT_TYPE.TSK_ENCRYPTION_DETECTED, Collections.singletonList(artifact)));
+
+ /*
+ * Make an ingest inbox message.
+ */
+ StringBuilder detailsSb = new StringBuilder();
+ detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("
\n");
+ detailsSb.append("Entropy: ").append(calculatedEntropy);
+
+ SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(),
+ "Encryption Detected Match: " + file.getName(),
+ detailsSb.toString(),
+ file.getName(),
+ artifact));
+
+ return IngestModule.ProcessResult.OK;
+ } catch (TskCoreException ex) {
+ LOGGER.log(Level.SEVERE, String.format("Failed to create blackboard artifact for '%s'.", Paths.get(file.getParentPath(), file.getName())), ex); //NON-NLS
+ return IngestModule.ProcessResult.ERROR;
+ }
+ }
+
+ /**
+ * This method checks if the AbstractFile input is encrypted. Initial
+ * qualifications require that it be an actual file that is not known, meets
+ * file size requirements, and has a MIME type of
+ * 'application/octet-stream'.
+ *
+ * @param file AbstractFile to be checked.
+ *
+ * @return True if the AbstractFile is encrypted.
+ */
+ private boolean isFileEncrypted(AbstractFile file) throws IOException, TskCoreException {
+ /*
+ * Criteria for the checks in this method are partially based on
+ * http://www.forensicswiki.org/wiki/TrueCrypt#Detection
+ */
+
+ boolean possiblyEncrypted = false;
+
+ /*
+ * Qualify the file type.
+ */
+ if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)
+ && !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)
+ && (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed)) {
+ /*
+ * Qualify the file against hash databases.
+ */
+ if (!file.getKnown().equals(TskData.FileKnown.KNOWN)) {
+ /*
+ * Qualify the size.
+ */
+ long contentSize = file.getSize();
+ if (contentSize >= minimumFileSize) {
+ if (!fileSizeMultipleEnforced || (contentSize % FILE_SIZE_MODULUS) == 0) {
+ /*
+ * Qualify the MIME type.
+ */
+ try {
+ String mimeType = fileTypeDetector.getFileType(file);
+ if (mimeType != null && mimeType.equals("application/octet-stream")) {
+ possiblyEncrypted = true;
+ }
+ } catch (TskCoreException ex) {
+ throw new TskCoreException("Failed to detect the file type.", ex);
+ }
+ }
+ }
+ }
+ }
+
+ if (possiblyEncrypted) {
+ try {
+ calculatedEntropy = calculateEntropy(file);
+ if (calculatedEntropy >= minimumEntropy) {
+ return true;
+ }
+ } catch (IOException ex) {
+ throw new IOException("Unable to calculate the entropy.", ex);
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Calculate the entropy of the file. The result is used to qualify the file
+ * as an encrypted file.
+ *
+ * @param file The file to be calculated against.
+ *
+ * @return The entropy of the file.
+ *
+ * @throws IOException If there is a failure closing or reading from the
+ * InputStream.
+ */
+ private double calculateEntropy(AbstractFile file) throws IOException {
+ /*
+ * Logic in this method is based on
+ * https://github.com/willjasen/entropy/blob/master/entropy.java
+ */
+
+ InputStream in = null;
+ BufferedInputStream bin = null;
+
+ try {
+ in = new ReadContentInputStream(file);
+ bin = new BufferedInputStream(in);
+
+ /*
+ * Determine the number of times each byte value appears.
+ */
+ int[] byteOccurences = new int[BYTE_OCCURENCES_BUFFER_SIZE];
+ int readByte;
+ while ((readByte = bin.read()) != -1) {
+ byteOccurences[readByte]++;
+ }
+
+ /*
+ * Calculate the entropy based on the byte occurence counts.
+ */
+ long dataLength = file.getSize() - 1;
+ double entropyAccumulator = 0;
+ for (int i = 0; i < BYTE_OCCURENCES_BUFFER_SIZE; i++) {
+ if (byteOccurences[i] > 0) {
+ double byteProbability = (double) byteOccurences[i] / (double) dataLength;
+ entropyAccumulator += (byteProbability * Math.log(byteProbability) * ONE_OVER_LOG2);
+ }
+ }
+
+ return -entropyAccumulator;
+
+ } catch (IOException ex) {
+ throw new IOException("IOException occurred while trying to read data from InputStream.", ex);
+ } finally {
+ try {
+ if (in != null) {
+ in.close();
+ }
+ if (bin != null) {
+ bin.close();
+ }
+ } catch (IOException ex) {
+ throw new IOException("Failed to close InputStream.", ex);
+ }
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java
new file mode 100755
index 0000000000..2aa6ad860d
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettings.java
@@ -0,0 +1,133 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 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.encryptiondetection;
+
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+
+/**
+ * Ingest job settings for the Encryption Detection module.
+ */
+final class EncryptionDetectionIngestJobSettings implements IngestModuleIngestJobSettings {
+
+ private static final long serialVersionUID = 1L;
+
+ private double minimumEntropy;
+ private int minimumFileSize;
+ private boolean fileSizeMultipleEnforced;
+ private boolean slackFilesAllowed;
+
+ /**
+ * Instantiate the ingest job settings with default values.
+ */
+ EncryptionDetectionIngestJobSettings() {
+ this.minimumEntropy = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_MINIMUM_ENTROPY;
+ this.minimumFileSize = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_MINIMUM_FILE_SIZE;
+ this.fileSizeMultipleEnforced = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED;
+ this.slackFilesAllowed = EncryptionDetectionFileIngestModule.DEFAULT_CONFIG_SLACK_FILES_ALLOWED;
+ }
+
+ /**
+ * Instantiate the ingest job settings.
+ *
+ * @param minimumEntropy The minimum entropy.
+ * @param minimumFileSize The minimum file size.
+ * @param fileSizeMultipleEnforced Files must be a multiple of 512 to be
+ * processed.
+ * @param slackFilesAllowed Slack files can be processed.
+ */
+ EncryptionDetectionIngestJobSettings(double minimumEntropy, int minimumFileSize, boolean fileSizeMultipleEnforced, boolean slackFilesAllowed) {
+ this.minimumEntropy = minimumEntropy;
+ this.minimumFileSize = minimumFileSize;
+ this.fileSizeMultipleEnforced = fileSizeMultipleEnforced;
+ this.slackFilesAllowed = slackFilesAllowed;
+ }
+
+ @Override
+ public long getVersionNumber() {
+ return serialVersionUID;
+ }
+
+ /**
+ * Get the minimum entropy necessary for the creation of blackboard
+ * artifacts.
+ *
+ * @return The minimum entropy.
+ */
+ double getMinimumEntropy() {
+ return minimumEntropy;
+ }
+
+ /**
+ * Set the minimum entropy necessary for the creation of blackboard
+ * artifacts.
+ */
+ void setMinimumEntropy(double minimumEntropy) {
+ this.minimumEntropy = minimumEntropy;
+ }
+
+ /**
+ * Get the minimum file size necessary for the creation of blackboard
+ * artifacts.
+ *
+ * @return The minimum file size.
+ */
+ int getMinimumFileSize() {
+ return minimumFileSize;
+ }
+
+ /**
+ * Set the minimum file size necessary for the creation of blackboard
+ * artifacts.
+ */
+ void setMinimumFileSize(int minimumFileSize) {
+ this.minimumFileSize = minimumFileSize;
+ }
+
+ /**
+ * Is the file size multiple enforced?
+ *
+ * @return True if enforcement is enabled; otherwise false.
+ */
+ boolean isFileSizeMultipleEnforced() {
+ return fileSizeMultipleEnforced;
+ }
+
+ /**
+ * Enable or disable file size multiple enforcement.
+ */
+ void setFileSizeMultipleEnforced(boolean fileSizeMultipleEnforced) {
+ this.fileSizeMultipleEnforced = fileSizeMultipleEnforced;
+ }
+
+ /**
+ * Are slack files allowed for processing?
+ *
+ * @return True if slack files are allowed; otherwise false.
+ */
+ boolean isSlackFilesAllowed() {
+ return slackFilesAllowed;
+ }
+
+ /**
+ * Allow or disallow slack files for processing.
+ */
+ void setSlackFilesAllowed(boolean slackFilesAllowed) {
+ this.slackFilesAllowed = slackFilesAllowed;
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form
new file mode 100755
index 0000000000..26c859fe4d
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.form
@@ -0,0 +1,132 @@
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java
new file mode 100755
index 0000000000..123a62ec85
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionIngestJobSettingsPanel.java
@@ -0,0 +1,201 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 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.encryptiondetection;
+
+import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+
+/**
+ * Ingest job settings panel for the Encryption Detection module.
+ */
+final class EncryptionDetectionIngestJobSettingsPanel extends IngestModuleIngestJobSettingsPanel {
+
+ private static final int MEGABYTE_SIZE = 1048576;
+ private static final double MINIMUM_ENTROPY_INPUT_RANGE_MIN = 6.0;
+ private static final double MINIMUM_ENTROPY_INPUT_RANGE_MAX = 8.0;
+ private static final int MINIMUM_FILE_SIZE_INPUT_RANGE_MIN = 1;
+
+ /**
+ * Instantiate the ingest job settings panel.
+ *
+ * @param settings The ingest job settings.
+ */
+ public EncryptionDetectionIngestJobSettingsPanel(EncryptionDetectionIngestJobSettings settings) {
+ initComponents();
+ customizeComponents(settings);
+ }
+
+ /**
+ * Update components with values from the ingest job settings.
+ *
+ * @param settings The ingest job settings.
+ */
+ private void customizeComponents(EncryptionDetectionIngestJobSettings settings) {
+ minimumEntropyTextbox.setText(String.valueOf(settings.getMinimumEntropy()));
+ minimumFileSizeTextbox.setText(String.valueOf(settings.getMinimumFileSize() / MEGABYTE_SIZE));
+ fileSizeMultiplesEnforcedCheckbox.setSelected(settings.isFileSizeMultipleEnforced());
+ slackFilesAllowedCheckbox.setSelected(settings.isSlackFilesAllowed());
+ }
+
+ @Override
+ public IngestModuleIngestJobSettings getSettings() {
+ validateMinimumEntropy();
+ validateMinimumFileSize();
+
+ return new EncryptionDetectionIngestJobSettings(
+ Double.valueOf(minimumEntropyTextbox.getText()),
+ Integer.valueOf(minimumFileSizeTextbox.getText()) * MEGABYTE_SIZE,
+ fileSizeMultiplesEnforcedCheckbox.isSelected(),
+ slackFilesAllowedCheckbox.isSelected());
+ }
+
+ /**
+ * Validate the minimum entropy input.
+ *
+ * @throws IllegalArgumentException If the input is empty, invalid, or out
+ * of range.
+ */
+ @Messages({
+ "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text=Minimum entropy input must be a number between 6.0 and 8.0."
+ })
+ private void validateMinimumEntropy() throws IllegalArgumentException {
+ try {
+ double minimumEntropy = Double.valueOf(minimumEntropyTextbox.getText());
+ if (minimumEntropy < MINIMUM_ENTROPY_INPUT_RANGE_MIN || minimumEntropy > MINIMUM_ENTROPY_INPUT_RANGE_MAX) {
+ throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text"));
+ }
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyInput.validationError.text"));
+ }
+ }
+
+ /**
+ * Validate the minimum file size input.
+ *
+ * @throws IllegalArgumentException If the input is empty, invalid, or out
+ * of range.
+ */
+ @Messages({
+ "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text=Minimum file size input must be an integer (in megabytes) of 1 or greater."
+ })
+ private void validateMinimumFileSize() throws IllegalArgumentException {
+ try {
+ int minimumFileSize = Integer.valueOf(minimumFileSizeTextbox.getText());
+ if (minimumFileSize < MINIMUM_FILE_SIZE_INPUT_RANGE_MIN) {
+ throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text"));
+ }
+ } catch (NumberFormatException ex) {
+ throw new IllegalArgumentException(NbBundle.getMessage(this.getClass(), "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeInput.validationError.text"));
+ }
+ }
+
+ /**
+ * This method is called from within the constructor to initialize the form.
+ * WARNING: Do NOT modify this code. The content of this method is always
+ * regenerated by the Form Editor.
+ */
+ @SuppressWarnings("unchecked")
+ // //GEN-BEGIN:initComponents
+ private void initComponents() {
+
+ minimumEntropyTextbox = new javax.swing.JTextField();
+ minimumFileSizeTextbox = new javax.swing.JTextField();
+ fileSizeMultiplesEnforcedCheckbox = new javax.swing.JCheckBox();
+ slackFilesAllowedCheckbox = new javax.swing.JCheckBox();
+ minimumEntropyLabel = new javax.swing.JLabel();
+ minimumFileSizeLabel = new javax.swing.JLabel();
+ mbLabel = new javax.swing.JLabel();
+ detectionSettingsLabel = new javax.swing.JLabel();
+
+ minimumEntropyTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text")); // NOI18N
+
+ minimumFileSizeTextbox.setText(org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(fileSizeMultiplesEnforcedCheckbox, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(slackFilesAllowedCheckbox, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(minimumEntropyLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(minimumFileSizeLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text")); // NOI18N
+
+ org.openide.awt.Mnemonics.setLocalizedText(mbLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.mbLabel.text")); // NOI18N
+
+ detectionSettingsLabel.setFont(new java.awt.Font("Tahoma", 1, 11)); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(detectionSettingsLabel, org.openide.util.NbBundle.getMessage(EncryptionDetectionIngestJobSettingsPanel.class, "EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text")); // NOI18N
+
+ javax.swing.GroupLayout layout = new javax.swing.GroupLayout(this);
+ this.setLayout(layout);
+ layout.setHorizontalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(slackFilesAllowedCheckbox)
+ .addComponent(detectionSettingsLabel)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+ .addComponent(minimumFileSizeLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+ .addComponent(minimumEntropyLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, 32, javax.swing.GroupLayout.PREFERRED_SIZE)))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(mbLabel))
+ .addComponent(fileSizeMultiplesEnforcedCheckbox))
+ .addContainerGap(15, Short.MAX_VALUE))
+ );
+ layout.setVerticalGroup(
+ layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addContainerGap()
+ .addComponent(detectionSettingsLabel)
+ .addGap(16, 16, 16)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(minimumEntropyTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(minimumEntropyLabel))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(minimumFileSizeTextbox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(mbLabel)
+ .addComponent(minimumFileSizeLabel))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(fileSizeMultiplesEnforcedCheckbox)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(slackFilesAllowedCheckbox)
+ .addContainerGap(160, Short.MAX_VALUE))
+ );
+ }// //GEN-END:initComponents
+
+ // Variables declaration - do not modify//GEN-BEGIN:variables
+ private javax.swing.JLabel detectionSettingsLabel;
+ private javax.swing.JCheckBox fileSizeMultiplesEnforcedCheckbox;
+ private javax.swing.JLabel mbLabel;
+ private javax.swing.JLabel minimumEntropyLabel;
+ private javax.swing.JTextField minimumEntropyTextbox;
+ private javax.swing.JLabel minimumFileSizeLabel;
+ private javax.swing.JTextField minimumFileSizeTextbox;
+ private javax.swing.JCheckBox slackFilesAllowedCheckbox;
+ // End of variables declaration//GEN-END:variables
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java
new file mode 100755
index 0000000000..27549f648f
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/encryptiondetection/EncryptionDetectionModuleFactory.java
@@ -0,0 +1,116 @@
+/*
+ * Autopsy Forensic Browser
+ *
+ * Copyright 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.encryptiondetection;
+
+import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
+import org.openide.util.lookup.ServiceProvider;
+import org.sleuthkit.autopsy.coreutils.Version;
+import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
+import org.sleuthkit.autopsy.ingest.FileIngestModule;
+import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
+import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
+import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
+
+/**
+ * A factory that creates file ingest modules that detect encryption.
+ */
+@ServiceProvider(service = IngestModuleFactory.class)
+@Messages({
+ "EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection",
+ "EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy."
+})
+public class EncryptionDetectionModuleFactory implements IngestModuleFactory {
+
+ @Override
+ public String getModuleDisplayName() {
+ return getModuleName();
+ }
+
+ /**
+ * Get the name of the module.
+ *
+ * @return The module name.
+ */
+ static String getModuleName() {
+ return NbBundle.getMessage(EncryptionDetectionFileIngestModule.class, "EncryptionDetectionFileIngestModule.moduleName.text");
+ }
+
+ @Override
+ public String getModuleDescription() {
+ return NbBundle.getMessage(EncryptionDetectionFileIngestModule.class, "EncryptionDetectionFileIngestModule.getDesc.text");
+ }
+
+ @Override
+ public String getModuleVersionNumber() {
+ return Version.getVersion();
+ }
+
+ @Override
+ public boolean isFileIngestModuleFactory() {
+ return true;
+ }
+
+ @Override
+ public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
+ if (!(settings instanceof EncryptionDetectionIngestJobSettings)) {
+ throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings.");
+ }
+ return new EncryptionDetectionFileIngestModule((EncryptionDetectionIngestJobSettings) settings);
+ }
+
+ @Override
+ public boolean hasGlobalSettingsPanel() {
+ return false;
+ }
+
+ @Override
+ public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() {
+ throw new UnsupportedOperationException();
+ }
+
+ @Override
+ public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
+ return new EncryptionDetectionIngestJobSettings();
+ }
+
+ @Override
+ public boolean hasIngestJobSettingsPanel() {
+ return true;
+ }
+
+ @Override
+ public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
+ if (!(settings instanceof EncryptionDetectionIngestJobSettings)) {
+ throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings");
+ }
+ return new EncryptionDetectionIngestJobSettingsPanel((EncryptionDetectionIngestJobSettings) settings);
+ }
+
+ @Override
+ public boolean isDataSourceIngestModuleFactory() {
+ return false;
+ }
+
+ @Override
+ public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) {
+ throw new UnsupportedOperationException();
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
index eb1ab33591..b1aff14a8f 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/filetypeid/FileTypeDetector.java
@@ -18,7 +18,9 @@
*/
package org.sleuthkit.autopsy.modules.filetypeid;
+import java.io.IOException;
import java.util.ArrayList;
+import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.SortedSet;
@@ -26,7 +28,9 @@ import java.util.TreeSet;
import java.util.logging.Level;
import java.util.stream.Collectors;
import org.apache.tika.Tika;
+import org.apache.tika.io.TikaInputStream;
import org.apache.tika.mime.MimeTypes;
+import org.openide.util.Exceptions;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
@@ -35,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute;
+import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
@@ -49,8 +54,6 @@ public class FileTypeDetector {
private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName());
private static final Tika tika = new Tika();
- private static final int BUFFER_SIZE = 64 * 1024;
- private final byte buffer[] = new byte[BUFFER_SIZE];
private final List userDefinedFileTypes;
private final List autopsyDefinedFileTypes;
private static SortedSet tikaDetectedTypes;
@@ -269,17 +272,11 @@ public class FileTypeDetector {
* bytes to Tika.
*/
if (null == mimeType) {
- try {
- byte buf[];
- int len = file.read(buffer, 0, BUFFER_SIZE);
- if (len < BUFFER_SIZE) {
- buf = new byte[len];
- System.arraycopy(buffer, 0, buf, 0, len);
- } else {
- buf = buffer;
- }
- String tikaType = tika.detect(buf, file.getName());
-
+ ReadContentInputStream stream = new ReadContentInputStream(file);
+
+ try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) {
+ String tikaType = tika.detect(tikaInputStream, file.getName());
+
/*
* Remove the Tika suffix from the MIME type name.
*/
@@ -360,8 +357,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 +367,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/Bundle.properties b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
index 3ec2961927..7e4b10fc5d 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/Bundle.properties
@@ -17,7 +17,7 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed.
HashDbSearchPanel.saveBox.text=Remember Hashes
HashDbSearchPanel.cancelButton.text=Cancel
OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools
-HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name:
+HashDbImportDatabaseDialog.jLabel1.text=Name:
HashDbImportDatabaseDialog.databasePathTextField.text=
HashDbImportDatabaseDialog.knownBadRadioButton.text=Notable
HashDbImportDatabaseDialog.jLabel2.text=Type of database\:
@@ -39,7 +39,7 @@ HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox mes
HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox message for each hit
HashDbImportDatabaseDialog.hashSetNameTextField.text=
HashDbImportDatabaseDialog.openButton.text=Open...
-HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name:
+HashDbCreateDatabaseDialog.jLabel3.text=Name:
HashDbCreateDatabaseDialog.okButton.text=OK
HashDbCreateDatabaseDialog.databasePathTextField.text=
AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured
@@ -205,7 +205,7 @@ HashLookupSettingsPanel.typeLabel.text=Type:
HashLookupSettingsPanel.locationLabel.text=Database Path:
HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected
HashLookupSettingsPanel.hashDbNameLabel.text=No database selected
-HashLookupSettingsPanel.nameLabel.text=Hash Set Name:
+HashLookupSettingsPanel.nameLabel.text=Name:
HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases:
HashLookupSettingsPanel.importDatabaseButton.toolTipText=
HashLookupSettingsPanel.importDatabaseButton.text=Import database
@@ -229,13 +229,13 @@ HashDbImportDatabaseDialog.lbVersion.text=Version:
HashDbImportDatabaseDialog.lbOrg.text=Source Organization:
HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only
HashDbImportDatabaseDialog.orgButton.text=Manage Organizations
-HashDbImportDatabaseDialog.versionTextField.text=
-HashDbImportDatabaseDialog.fileTypeRadioButton.text=File
-HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository
-HashDbImportDatabaseDialog.jLabel4.text=Location:
-HashDbCreateDatabaseDialog.jLabel4.text=Location:
-HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File
-HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository
+HashDbImportDatabaseDialog.versionTextField.text=1.0
+HashDbImportDatabaseDialog.fileTypeRadioButton.text=Local
+HashDbImportDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository)
+HashDbImportDatabaseDialog.jLabel4.text=Destination:
+HashDbCreateDatabaseDialog.jLabel4.text=Destination:
+HashDbCreateDatabaseDialog.fileTypeRadioButton.text=Local
+HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Remote (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/EncaseHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/EncaseHashSetParser.java
new file mode 100644
index 0000000000..4c6a58d9bf
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/EncaseHashSetParser.java
@@ -0,0 +1,168 @@
+/*
+ * 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)) {
+ throw new TskCoreException("Ran out of data unexpectedly while parsing Encase file " + filename);
+ }
+ }
+}
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java
index 0ecb3a5ad4..13dd9bcd63 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbCreateDatabaseDialog.java
@@ -33,6 +33,7 @@ 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.EamDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet;
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
@@ -154,8 +155,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
orgs = dbManager.getOrganizations();
orgs.forEach((org) -> {
orgComboBox.addItem(org.getName());
+ if(EamDbUtil.isDefaultOrg(org)){
+ orgComboBox.setSelectedItem(org.getName());
+ selectedOrg = org;
+ }
});
- if (!orgs.isEmpty()) {
+ if ((selectedOrg == null) && (!orgs.isEmpty())) {
selectedOrg = orgs.get(0);
}
} catch (EamDbException ex) {
@@ -423,7 +428,7 @@ 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 and version already exists",
+ "HashDbCreateDatabaseDialog.duplicateName=A hashset with this name already exists",
"HashDbCreateDatabaseDialog.databaseLookupError=Error accessing central repository",
"HashDbCreateDatabaseDialog.databaseCreationError=Error creating new hash set"
})
@@ -500,7 +505,7 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
} else {
// Check if a hash set with the same name/version already exists
try{
- if(EamDb.getInstance().referenceSetExists(hashSetNameTextField.getText(), EamDb.getDefaultVersion())){
+ if(EamDb.getInstance().referenceSetExists(hashSetNameTextField.getText(), "")){
JOptionPane.showMessageDialog(this,
NbBundle.getMessage(this.getClass(),
"HashDbCreateDatabaseDialog.duplicateName"),
@@ -522,9 +527,9 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
try{
int referenceSetID = EamDb.getInstance().newReferenceSet(new EamGlobalSet(selectedOrg.getOrgID(), hashSetNameTextField.getText(),
- EamDb.getDefaultVersion(), fileKnown, false));
+ "", fileKnown, false));
newHashDb = HashDbManager.getInstance().addExistingCentralRepoHashSet(hashSetNameTextField.getText(),
- EamDb.getDefaultVersion(), referenceSetID,
+ "", referenceSetID,
true, sendIngestMessagesCheckbox.isSelected(), type, false);
} catch (EamDbException | TskCoreException ex){
Logger.getLogger(HashDbImportDatabaseDialog.class.getName()).log(Level.SEVERE, "Error creating new reference set", ex);
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form
index 682ec13c34..dbb9f7b4e3 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.form
@@ -33,17 +33,37 @@
-
-
+
+
+
+
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
-
-
+
+
+
+
+
+
+
-
+
@@ -52,96 +72,87 @@
-
-
+
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
-
-
+
+
-
-
-
+
-
-
+
-
-
-
-
-
-
-
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java
index d32fc3cf9c..0c5d94277b 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbImportDatabaseDialog.java
@@ -34,6 +34,7 @@ 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.EamDbUtil;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -84,25 +85,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
private void initFileChooser() {
fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
- updateFileChooserFilter();
+ String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS
+ FileNameExtensionFilter filter = new FileNameExtensionFilter(
+ NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION);
+ fileChooser.setFileFilter(filter);
fileChooser.setMultiSelectionEnabled(false);
}
-
- @NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.idx only)"})
- private void updateFileChooserFilter() {
- fileChooser.resetChoosableFileFilters();
- if(centralRepoRadioButton.isSelected()){
- String[] EXTENSION = new String[]{"idx"}; //NON-NLS
- FileNameExtensionFilter filter = new FileNameExtensionFilter(
- NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.centralRepoExtFilter.text"), EXTENSION);
- fileChooser.setFileFilter(filter);
- } else {
- String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS
- FileNameExtensionFilter filter = new FileNameExtensionFilter(
- NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION);
- fileChooser.setFileFilter(filter);
- }
- }
private void display() {
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
@@ -148,8 +136,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
orgs = dbManager.getOrganizations();
orgs.forEach((org) -> {
orgComboBox.addItem(org.getName());
+ if(EamDbUtil.isDefaultOrg(org)){
+ orgComboBox.setSelectedItem(org.getName());
+ selectedOrg = org;
+ }
});
- if (!orgs.isEmpty()) {
+ if ((selectedOrg == null) && (!orgs.isEmpty())) {
selectedOrg = orgs.get(0);
}
} catch (EamDbException ex) {
@@ -303,95 +295,102 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
- .addGap(0, 325, Short.MAX_VALUE)
- .addComponent(okButton)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(jLabel3)
+ .addComponent(jLabel4))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(cancelButton))
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup()
+ .addComponent(fileTypeRadioButton)
+ .addGap(26, 26, 26)
+ .addComponent(centralRepoRadioButton)
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
+ .addGroup(layout.createSequentialGroup()
+ .addComponent(databasePathTextField)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(openButton)
+ .addContainerGap())))
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+ .addComponent(sendIngestMessagesCheckbox)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(okButton))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(lbOrg)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(orgComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
+ .addComponent(orgComboBox, 0, 121, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(orgButton))
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
+ .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1)
.addComponent(lbVersion))
- .addGap(2, 2, 2)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGap(40, 40, 40)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(versionTextField)
- .addComponent(hashSetNameTextField)))
- .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(jLabel3)
- .addComponent(jLabel4))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createSequentialGroup()
- .addComponent(fileTypeRadioButton)
- .addGap(26, 26, 26)
- .addComponent(centralRepoRadioButton))
- .addComponent(databasePathTextField))))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(openButton))
+ .addComponent(hashSetNameTextField))))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
+ .addComponent(cancelButton)
+ .addContainerGap())
.addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2)
+ .addComponent(readOnlyCheckbox)
.addGroup(layout.createSequentialGroup()
.addGap(19, 19, 19)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownRadioButton)
- .addComponent(knownBadRadioButton)))
- .addComponent(sendIngestMessagesCheckbox)
- .addComponent(readOnlyCheckbox))
- .addGap(0, 0, Short.MAX_VALUE)))
- .addContainerGap())
+ .addComponent(knownBadRadioButton))))
+ .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
);
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()
+ .addGroup(layout.createSequentialGroup()
.addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(fileTypeRadioButton)
- .addComponent(centralRepoRadioButton)
- .addComponent(jLabel4))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(openButton)
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(jLabel3))
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(jLabel1)
- .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(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(lbVersion))
- .addGap(9, 9, 9)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(orgButton)
- .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(lbOrg))
- .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.RELATED)
- .addComponent(readOnlyCheckbox)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
- .addComponent(sendIngestMessagesCheckbox)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(okButton)
- .addComponent(cancelButton))
+ .addComponent(jLabel3)
+ .addComponent(openButton))
+ .addGap(18, 18, 18)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addGroup(layout.createSequentialGroup()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(fileTypeRadioButton)
+ .addComponent(centralRepoRadioButton)
+ .addComponent(jLabel4))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(jLabel1)
+ .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(lbVersion)
+ .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addGap(5, 5, 5)
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
+ .addComponent(orgButton)
+ .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(lbOrg))
+ .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.RELATED)
+ .addComponent(readOnlyCheckbox)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(sendIngestMessagesCheckbox)
+ .addGap(0, 21, 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())
);
@@ -409,7 +408,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
hashDbFolder.mkdir();
}
fileChooser.setCurrentDirectory(hashDbFolder);
- updateFileChooserFilter();
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile();
try {
@@ -447,7 +445,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
@@ -456,7 +455,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);
@@ -464,7 +463,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"),
@@ -557,7 +556,7 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
version = versionTextField.getText();
} else {
// Editable databases don't have a version
- version = EamDb.getDefaultVersion();
+ version = "";
}
ImportCentralRepoDbProgressDialog progressDialog = new ImportCentralRepoDbProgressDialog();
progressDialog.importFile(hashSetNameTextField.getText(), version,
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbIngestModule.java
index 16bcb1d2e9..f022f6b657 100644
--- 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;
@@ -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
index 8e0f5422a1..34770aa6fa 100644
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashDbManager.java
@@ -728,8 +728,6 @@ public class HashDbManager implements PropertyChangeListener {
public abstract HashDb.KnownFilesType getKnownFilesType();
public abstract boolean getSearchDuringIngest();
-
- abstract boolean getDefaultSearchDuringIngest();
abstract void setSearchDuringIngest(boolean useForIngest);
@@ -869,12 +867,6 @@ public class HashDbManager implements PropertyChangeListener {
public boolean getSearchDuringIngest() {
return searchDuringIngest;
}
-
- @Override
- boolean getDefaultSearchDuringIngest(){
- // File type hash sets are on by default
- return true;
- }
@Override
void setSearchDuringIngest(boolean useForIngest) {
@@ -1176,12 +1168,6 @@ public class HashDbManager implements PropertyChangeListener {
public boolean getSearchDuringIngest() {
return searchDuringIngest;
}
-
- @Override
- boolean getDefaultSearchDuringIngest(){
- // Central repo hash sets are off by default
- return false;
- }
@Override
void setSearchDuringIngest(boolean useForIngest) {
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java
index 3e331cb1da..99dd50d291 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupModuleSettings.java
@@ -135,8 +135,8 @@ final class HashLookupModuleSettings implements IngestModuleIngestJobSettings {
}
}
- // We didn't find it, so use the default value
- return db.getDefaultSearchDuringIngest();
+ // We didn't find it, so use the value in the HashDb object
+ return db.getSearchDuringIngest();
}
/**
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
index 5be552d274..d32cbf57d7 100755
--- a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.form
@@ -105,28 +105,6 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
@@ -143,6 +121,25 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashLookupSettingsPanel.java
index b5c6ca805a..1adb75594d 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 new central repo hash sets. They don't need to be
+ // indexed so will all be saved on both code paths.
+ 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,19 @@ 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 +399,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 +472,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));
}
@@ -509,7 +511,7 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
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 +544,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) {
@@ -785,24 +787,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(locationLabel)
- .addComponent(typeLabel)
- .addComponent(versionLabel)
- .addComponent(orgLabel)
- .addComponent(readOnlyLabel))
- .addGap(55, 55, 55)
- .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addComponent(hashDbVersionLabel)
- .addComponent(hashDbOrgLabel)
- .addComponent(hashDbReadOnlyLabel)))
- .addGroup(jPanel1Layout.createSequentialGroup()
- .addComponent(nameLabel)
- .addGap(53, 53, 53)
- .addComponent(hashDbNameLabel))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE)
@@ -814,7 +798,23 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(10, 10, 10)
- .addComponent(addHashesToDatabaseButton))))
+ .addComponent(addHashesToDatabaseButton))
+ .addGroup(jPanel1Layout.createSequentialGroup()
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(locationLabel)
+ .addComponent(typeLabel)
+ .addComponent(versionLabel)
+ .addComponent(orgLabel)
+ .addComponent(readOnlyLabel)
+ .addComponent(nameLabel))
+ .addGap(55, 55, 55)
+ .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(hashDbNameLabel)
+ .addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(hashDbVersionLabel)
+ .addComponent(hashDbOrgLabel)
+ .addComponent(hashDbReadOnlyLabel)))))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(70, 70, 70)
.addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE))
@@ -933,11 +933,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();
+ if (hashDb instanceof CentralRepoHashSet) {
+ int newDbIndex = ((CentralRepoHashSet) hashDb).getReferenceSetID();
newReferenceSetIDs.add(newDbIndex);
}
-
+
hashSetTableModel.refreshModel();
((HashSetTable) hashSetTable).selectRowByDatabase(hashDb);
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
@@ -959,7 +959,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) {
@@ -987,11 +987,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);
@@ -1001,21 +1001,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/HashkeeperHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java
new file mode 100644
index 0000000000..e66af62eb3
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/HashkeeperHashSetParser.java
@@ -0,0 +1,133 @@
+/*
+ * 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.File;
+import java.io.InputStreamReader;
+import java.io.FileInputStream;
+import java.io.IOException;
+import java.util.logging.Level;
+import java.util.Iterator;
+import org.apache.commons.csv.CSVFormat;
+import org.apache.commons.csv.CSVParser;
+import org.apache.commons.csv.CSVRecord;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.datamodel.TskCoreException;
+
+/**
+ * Parser for Hashkeeper hash sets (*.hsh)
+ */
+public class HashkeeperHashSetParser implements HashSetParser {
+
+ private String filename;
+ private InputStreamReader inputStreamReader;
+ private CSVParser csvParser;
+ private final long expectedHashCount; // Number of hashes we expect to read from the file
+ private final Iterator recordIterator;
+ private final int hashColumnIndex; // The index of the hash column
+
+ HashkeeperHashSetParser(String filename) throws TskCoreException {
+ this.filename = filename;
+
+ try {
+ // Estimate the total number of hashes in the file
+ File importFile = new File(filename);
+ long fileSize = importFile.length();
+ expectedHashCount = fileSize / 75 + 1; // As a rough estimate, assume 75 bytes per line. We add one to prevent this from being zero
+
+ // Create the parser
+ inputStreamReader = new InputStreamReader(new FileInputStream(filename)); //NON-NLS
+ csvParser = CSVFormat.RFC4180.withFirstRecordAsHeader().parse(inputStreamReader);
+ if (!csvParser.getHeaderMap().keySet().contains("hash")) {
+ close();
+ throw new TskCoreException("Hashkeeper file format invalid - does not contain 'hash' column");
+ }
+
+ // For efficiency, store the index of the hash column
+ hashColumnIndex = csvParser.getHeaderMap().get("hash");
+
+ // Make an iterator to loop over the entries
+ recordIterator = csvParser.getRecords().listIterator();
+
+ // We're ready to use recordIterator to get each hash
+ } catch (IOException ex) {
+ close();
+ throw new TskCoreException("Error reading " + filename, ex);
+ }
+ }
+
+ /**
+ * 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 (recordIterator.hasNext()) {
+ CSVRecord record = recordIterator.next();
+ String hash = record.get(hashColumnIndex);
+
+ if (hash.length() != 32) {
+ throw new TskCoreException("Hash has incorrect length: " + hash);
+ }
+
+ return (hash);
+ }
+ 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 (!recordIterator.hasNext());
+ }
+
+ /**
+ * 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;
+ }
+
+ /**
+ * Closes the import file
+ */
+ @Override
+ public final void close() {
+ if (inputStreamReader != null) {
+ try {
+ inputStreamReader.close();
+ } catch (IOException ex) {
+ Logger.getLogger(HashkeeperHashSetParser.class.getName()).log(Level.SEVERE, "Error closing Hashkeeper hash set " + filename, ex);
+ } finally {
+ inputStreamReader = null;
+ }
+ }
+ }
+}
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..0db5442c0c
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/IdxHashSetParser.java
@@ -0,0 +1,121 @@
+/*
+ * 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 and md5sum files (*.idx or *.txt) This parsers lines
+ * that start with md5 hashes and ignores any others
+ */
+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
+ // MD5sum output lines should be close enough to that (0x20 byte hash + filename)
+ }
+
+ /**
+ * 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) {
+
+ // idx files have a pipe after the hash, md5sum files should have a space
+ String[] parts = line.split("\\|| ");
+
+ String hashStr = parts[0].toLowerCase();
+ if (!hashStr.matches("^[0-9a-f]{32}$")) {
+ continue;
+ }
+
+ return hashStr;
+ }
+ } 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..37d3a20009 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,165 @@ 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") || importFileName.toLowerCase().endsWith(".txt")) {
+ hashSetParser = new IdxHashSetParser(importFileName);
+ } else if (importFileName.toLowerCase().endsWith(".hash")) {
+ hashSetParser = new EncaseHashSetParser(importFileName);
+ } else if (importFileName.toLowerCase().endsWith(".kdb")) {
+ hashSetParser = new KdbHashSetParser(importFileName);
+ } else if (importFileName.toLowerCase().endsWith(".hsh")) {
+ hashSetParser = new HashkeeperHashSetParser(importFileName);
} else {
- knownStatus = TskData.FileKnown.BAD;
+ // 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/hashdatabase/KdbHashSetParser.java b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java
new file mode 100644
index 0000000000..5935784087
--- /dev/null
+++ b/Core/src/org/sleuthkit/autopsy/modules/hashdatabase/KdbHashSetParser.java
@@ -0,0 +1,160 @@
+/*
+ * 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.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.logging.Level;
+import org.sleuthkit.autopsy.coreutils.Logger;
+import org.sleuthkit.datamodel.TskCoreException;
+
+/**
+ * Parser for Autopsy/TSK-created databases (*.kdb)
+ */
+public class KdbHashSetParser implements HashSetParser {
+
+ private final String JDBC_DRIVER = "org.sqlite.JDBC"; // NON-NLS
+ private final String JDBC_BASE_URI = "jdbc:sqlite:"; // NON-NLS
+
+ private final String filename; // Name of the input file (saved for logging)
+ private final long totalHashes; // Estimated number of hashes
+ private int totalHashesRead = 0; // Number of hashes that have been read
+ private Connection conn;
+ private Statement statement;
+ private ResultSet resultSet;
+
+ KdbHashSetParser(String filename) throws TskCoreException {
+ this.filename = filename;
+
+ conn = null;
+ statement = null;
+ resultSet = null;
+
+ try {
+ // Open the database
+ StringBuilder connectionURL = new StringBuilder();
+ connectionURL.append(JDBC_BASE_URI);
+ connectionURL.append(filename);
+ Class.forName(JDBC_DRIVER);
+ conn = DriverManager.getConnection(connectionURL.toString());
+
+ // Get the number of hashes in the table
+ statement = conn.createStatement();
+ resultSet = statement.executeQuery("SELECT count(*) AS count FROM hashes");
+ if (resultSet.next()) {
+ totalHashes = resultSet.getLong("count");
+ } else {
+ close();
+ throw new TskCoreException("Error getting hash count from database " + filename);
+ }
+
+ // Get the hashes
+ resultSet = statement.executeQuery("SELECT md5 FROM hashes");
+
+ // At this point, getNextHash can read each hash from the result set
+ } catch (ClassNotFoundException | SQLException ex) {
+ throw new TskCoreException("Error opening/reading database " + filename, ex);
+ }
+
+ }
+
+ /**
+ * Get the next hash to import
+ *
+ * @return The hash as a string
+ * @throws TskCoreException
+ */
+ @Override
+ public String getNextHash() throws TskCoreException {
+
+ try {
+ if (resultSet.next()) {
+ byte[] hashBytes = resultSet.getBytes("md5");
+ StringBuilder sb = new StringBuilder();
+ for (byte b : hashBytes) {
+ sb.append(String.format("%02x", b));
+ }
+
+ if (sb.toString().length() != 32) {
+ throw new TskCoreException("Hash has incorrect length: " + sb.toString());
+ }
+
+ totalHashesRead++;
+ return sb.toString();
+ } else {
+ throw new TskCoreException("Could not read expected number of hashes from database " + filename);
+ }
+ } catch (SQLException ex) {
+ throw new TskCoreException("Error reading hash from result set for database " + filename, ex);
+ }
+ }
+
+ /**
+ * 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 >= totalHashes);
+ }
+
+ /**
+ * Get the expected number of hashes in the file.
+ *
+ * @return The expected hash count
+ */
+ @Override
+ public long getExpectedHashCount() {
+ return totalHashes;
+ }
+
+ /**
+ * Closes the import file
+ */
+ @Override
+ public final void close() {
+ if (statement != null) {
+ try {
+ statement.close();
+ } catch (SQLException ex) {
+ Logger.getLogger(KdbHashSetParser.class.getName()).log(Level.SEVERE, "Error closing prepared statement.", ex);
+ }
+ }
+
+ if (resultSet != null) {
+ try {
+ resultSet.close();
+ } catch (SQLException ex) {
+ Logger.getLogger(KdbHashSetParser.class.getName()).log(Level.SEVERE, "Error closing result set.", ex);
+ }
+ }
+
+ if (conn != null) {
+ try {
+ conn.close();
+ } catch (SQLException ex) {
+ Logger.getLogger(KdbHashSetParser.class.getName()).log(Level.SEVERE, "Error closing connection.", ex);
+ }
+ }
+ }
+}
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/report/ReportHTML.java b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java
index c03c37a09b..aab7eaae97 100755
--- a/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java
+++ b/Core/src/org/sleuthkit/autopsy/report/ReportHTML.java
@@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
class ReportHTML implements TableReportModule {
@@ -688,7 +689,8 @@ class ReportHTML implements TableReportModule {
}
for (int i = 0; i < tags.size(); i++) {
ContentTag tag = tags.get(i);
- linkToThumbnail.append(tag.getName().getDisplayName());
+ String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ linkToThumbnail.append(tag.getName().getDisplayName() + notableString);
if (i != tags.size() - 1) {
linkToThumbnail.append(", ");
}
diff --git a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
index 08ec3d0151..53422c8f0d 100755
--- a/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
+++ b/Core/src/org/sleuthkit/autopsy/report/ReportVisualPanel2.java
@@ -41,10 +41,12 @@ import javax.swing.event.ListDataListener;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
final class ReportVisualPanel2 extends JPanel {
@@ -102,7 +104,8 @@ final class ReportVisualPanel2 extends JPanel {
}
for (TagName tagName : tagNamesInUse) {
- tagStates.put(tagName.getDisplayName(), Boolean.FALSE);
+ String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ tagStates.put(tagName.getDisplayName() + notableString, Boolean.FALSE);
}
tags.addAll(tagStates.keySet());
diff --git a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java
index 6de7e62f86..976804f1e7 100755
--- a/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java
+++ b/Core/src/org/sleuthkit/autopsy/report/TableReportGenerator.java
@@ -39,6 +39,7 @@ import java.util.TreeSet;
import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
@@ -305,7 +306,8 @@ class TableReportGenerator {
// Give the modules the rows for the content tags.
for (ContentTag tag : tags) {
// skip tags that we are not reporting on
- if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) {
+ String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) {
continue;
}
@@ -316,7 +318,7 @@ class TableReportGenerator {
fileName = tag.getContent().getName();
}
- ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment()));
+ ArrayList rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName() + notableString, fileName, tag.getComment()));
Content content = tag.getContent();
if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content;
@@ -382,12 +384,13 @@ class TableReportGenerator {
// Give the modules the rows for the content tags.
for (BlackboardArtifactTag tag : tags) {
- if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) {
+ String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) {
continue;
}
List row;
- row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName(), tag.getComment(), tag.getContent().getName()));
+ row = new ArrayList<>(Arrays.asList(tag.getArtifact().getArtifactTypeName(), tag.getName().getDisplayName() + notableString, tag.getComment(), tag.getContent().getName()));
tableReport.addRow(row);
// check if the tag is an image that we should later make a thumbnail for
@@ -969,7 +972,8 @@ class TableReportGenerator {
try {
List contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content);
for (ContentTag ct : contentTags) {
- allTags.add(ct.getName().getDisplayName());
+ String notableString = ct.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ allTags.add(ct.getName().getDisplayName() + notableString);
}
} catch (TskCoreException ex) {
errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags"));
@@ -1006,7 +1010,8 @@ class TableReportGenerator {
List tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact);
HashSet uniqueTagNames = new HashSet<>();
for (BlackboardArtifactTag tag : tags) {
- uniqueTagNames.add(tag.getName().getDisplayName());
+ String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ uniqueTagNames.add(tag.getName().getDisplayName() + notableString);
}
if (failsTagFilter(uniqueTagNames, tagNamesFilter)) {
continue;
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/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java
index dd4cb60377..40537d3b83 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJob.java
@@ -38,10 +38,10 @@ import org.sleuthkit.autopsy.ingest.IngestJob;
* ingest service.
*/
@ThreadSafe
-public final class AutoIngestJob implements Comparable, Serializable {
+final class AutoIngestJob implements Comparable, Serializable {
private static final long serialVersionUID = 1L;
- private static final int CURRENT_VERSION = 1;
+ private static final int CURRENT_VERSION = 2;
private static final int DEFAULT_PRIORITY = 0;
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
@@ -82,6 +82,12 @@ public final class AutoIngestJob implements Comparable, Serializa
private int numberOfCrashes;
@GuardedBy("this")
private StageDetails stageDetails;
+
+ /*
+ * Version 2 fields.
+ */
+ @GuardedBy("this")
+ private long dataSourceSize;
/**
* Constructs a new automated ingest job. All job state not specified in the
@@ -114,6 +120,11 @@ public final class AutoIngestJob implements Comparable, Serializa
this.processingStatus = ProcessingStatus.PENDING;
this.numberOfCrashes = 0;
this.stageDetails = this.getProcessingStageDetails();
+
+ /*
+ * Version 2 fields.
+ */
+ this.dataSourceSize = 0;
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
@@ -151,6 +162,11 @@ public final class AutoIngestJob implements Comparable, Serializa
this.processingStatus = nodeData.getProcessingStatus();
this.numberOfCrashes = nodeData.getNumberOfCrashes();
this.stageDetails = this.getProcessingStageDetails();
+
+ /*
+ * Version 2 fields.
+ */
+ this.dataSourceSize = nodeData.getDataSourceSize();
} catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
}
@@ -462,6 +478,24 @@ public final class AutoIngestJob implements Comparable, Serializa
this.numberOfCrashes = numberOfCrashes;
}
+ /**
+ * Gets the total size of the data source.
+ *
+ * @return The data source size.
+ */
+ synchronized long getDataSourceSize() {
+ return dataSourceSize;
+ }
+
+ /**
+ * Sets the total size of the data source.
+ *
+ * @param dataSourceSize The data source size.
+ */
+ synchronized void setDataSourceSize(long dataSourceSize) {
+ this.dataSourceSize = dataSourceSize;
+ }
+
/**
* Indicates whether some other job is "equal to" this job. Two jobs are
* equal if they have the same manifest file path.
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java
index e2b267fded..f367fdf553 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestJobNodeData.java
@@ -31,7 +31,7 @@ import javax.lang.model.type.TypeKind;
*/
final class AutoIngestJobNodeData {
- private static final int CURRENT_VERSION = 1;
+ private static final int CURRENT_VERSION = 2;
private static final int DEFAULT_PRIORITY = 0;
/*
@@ -47,7 +47,7 @@ final class AutoIngestJobNodeData {
* data. This avoids the need to continuously enlarge the buffer. Once the
* buffer has all the necessary data, it will be resized as appropriate.
*/
- private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131629;
+ private static final int MAX_POSSIBLE_NODE_DATA_SIZE = 131637;
/*
* Version 0 fields.
@@ -73,6 +73,11 @@ final class AutoIngestJobNodeData {
private long processingStageStartDate;
private String processingStageDetailsDescription; // 'byte' length used in byte array
private long processingStageDetailsStartDate;
+
+ /*
+ * Version 2 fields.
+ */
+ private long dataSourceSize;
/**
* Gets the current version of the auto ingest job coordination service node
@@ -109,6 +114,7 @@ final class AutoIngestJobNodeData {
setProcessingStage(job.getProcessingStage());
setProcessingStageStartDate(job.getProcessingStageStartDate());
setProcessingStageDetails(job.getProcessingStageDetails());
+ setDataSourceSize(job.getDataSourceSize());
}
/**
@@ -143,6 +149,7 @@ final class AutoIngestJobNodeData {
this.processingStageStartDate = 0L;
this.processingStageDetailsDescription = "";
this.processingStageDetailsStartDate = 0L;
+ this.dataSourceSize = 0L;
/*
* Get fields from node data.
@@ -179,6 +186,13 @@ final class AutoIngestJobNodeData {
this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT);
}
+ if (buffer.hasRemaining()) {
+ /*
+ * Get version 2 fields.
+ */
+ this.dataSourceSize = buffer.getLong();
+ }
+
} catch (BufferUnderflowException ex) {
throw new InvalidDataException("Node data is incomplete", ex);
}
@@ -498,6 +512,24 @@ final class AutoIngestJobNodeData {
void setProcessingHostName(String processingHost) {
this.processingHostName = processingHost;
}
+
+ /**
+ * Gets the total size of the data source.
+ *
+ * @return The data source size.
+ */
+ long getDataSourceSize() {
+ return this.dataSourceSize;
+ }
+
+ /**
+ * Sets the total size of the data source.
+ *
+ * @param dataSourceSize The data source size.
+ */
+ void setDataSourceSize(long dataSourceSize) {
+ this.dataSourceSize = dataSourceSize;
+ }
/**
* Gets the node data as a byte array that can be sent to the coordination
@@ -515,7 +547,7 @@ final class AutoIngestJobNodeData {
buffer.putLong(this.completedDate);
buffer.putInt(this.errorsOccurred ? 1 : 0);
- if (this.version > 0) {
+ if (this.version >= 1) {
// Write version
buffer.putInt(this.version);
@@ -531,6 +563,10 @@ final class AutoIngestJobNodeData {
putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE);
buffer.putLong(this.processingStageDetailsStartDate);
putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT);
+
+ if (this.version >= 2) {
+ buffer.putLong(this.dataSourceSize);
+ }
}
// Prepare the array
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
index 35b563b961..83337c551b 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestManager.java
@@ -56,7 +56,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.logging.Level;
-import java.util.stream.Collectors;
import javax.annotation.concurrent.GuardedBy;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case;
@@ -98,6 +97,9 @@ import org.sleuthkit.autopsy.ingest.IngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestJobStartResult;
import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleError;
+import org.sleuthkit.datamodel.Content;
+import org.sleuthkit.datamodel.DataSource;
+import org.sleuthkit.datamodel.SleuthkitCase;
/**
* An auto ingest manager is responsible for processing auto ingest jobs defined
@@ -2263,6 +2265,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
return;
}
+ collectMetrics(caseForJob.getSleuthkitCase(), dataSource);
exportFiles(dataSource);
}
@@ -2544,6 +2547,39 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
}
}
+ /**
+ * Gather metrics to store in auto ingest job nodes. A SleuthkitCase
+ * instance is used to get the content size.
+ *
+ * @param caseDb The SleuthkitCase instance.
+ * @param dataSource The auto ingest data source.
+ *
+ * @throws CoordinationServiceException If there's a problem retrieving
+ * data from the coordination
+ * service.
+ * @throws InterruptedException If the thread calling the
+ * coordination service is
+ * interrupted.
+ */
+ private void collectMetrics(SleuthkitCase caseDb, AutoIngestDataSource dataSource) throws CoordinationServiceException, InterruptedException {
+ /*
+ * Get the data source size and store it in the current job.
+ */
+ List contentList = dataSource.getContent();
+ long dataSourceSize = 0;
+ for (Content content : contentList) {
+ dataSourceSize += ((DataSource) content).getContentSize(caseDb);
+ }
+ currentJob.setDataSourceSize(dataSourceSize);
+
+ /*
+ * Create node data from the current job and store it.
+ */
+ AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(currentJob);
+ String manifestNodePath = currentJob.getManifest().getFilePath().toString();
+ coordinationService.setNodeData(CoordinationService.CategoryNode.MANIFESTS, manifestNodePath, nodeData.toArray());
+ }
+
/**
* Exports any files from the data source for the current job that
* satisfy any user-defined file export rules.
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java
index 9567b70470..7b07a15aec 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsCollector.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2017 Basis Technology Corp.
+ * Copyright 2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -29,14 +29,15 @@ import org.sleuthkit.autopsy.coreutils.Logger;
* Collects metrics for an auto ingest cluster.
*/
final class AutoIngestMetricsCollector {
-
+
private static final Logger LOGGER = Logger.getLogger(AutoIngestMetricsCollector.class.getName());
+ private static final int MINIMUM_SUPPORTED_JOB_NODE_VERSION = 1;
private CoordinationService coordinationService;
-
+
/**
* Creates an instance of the AutoIngestMetricsCollector.
- *
- * @throws AutoIngestMetricsCollector.AutoIngestMetricsCollectorException
+ *
+ * @throws AutoIngestMetricsCollector.AutoIngestMetricsCollectorException
*/
AutoIngestMetricsCollector() throws AutoIngestMetricsCollectorException {
try {
@@ -45,7 +46,7 @@ final class AutoIngestMetricsCollector {
throw new AutoIngestMetricsCollectorException("Failed to get coordination service", ex); //NON-NLS
}
}
-
+
/**
* Gets a new metrics snapshot from the coordination service for an auto
* ingest cluster.
@@ -59,7 +60,7 @@ final class AutoIngestMetricsCollector {
for (String node : nodeList) {
try {
AutoIngestJobNodeData nodeData = new AutoIngestJobNodeData(coordinationService.getNodeData(CoordinationService.CategoryNode.MANIFESTS, node));
- if (nodeData.getVersion() < 1) {
+ if (nodeData.getVersion() < MINIMUM_SUPPORTED_JOB_NODE_VERSION) {
/*
* Ignore version '0' nodes that have not been
* "upgraded" since they don't carry enough data.
@@ -78,7 +79,7 @@ final class AutoIngestMetricsCollector {
*/
break;
case COMPLETED:
- newMetricsSnapshot.addCompletedJobDate(job.getCompletedDate());
+ newMetricsSnapshot.addCompletedJobMetric(job.getCompletedDate(), job.getDataSourceSize());
break;
default:
LOGGER.log(Level.SEVERE, "Unknown AutoIngestJobData.ProcessingStatus");
@@ -92,41 +93,80 @@ final class AutoIngestMetricsCollector {
LOGGER.log(Level.SEVERE, String.format("Failed to create a job for '%s'", node), ex);
}
}
-
+
return newMetricsSnapshot;
-
+
} catch (CoordinationService.CoordinationServiceException ex) {
LOGGER.log(Level.SEVERE, "Failed to get node list from coordination service", ex);
return new MetricsSnapshot();
}
}
-
+
/**
* A snapshot of metrics for an auto ingest cluster.
*/
static final class MetricsSnapshot {
-
- private final List completedJobDates = new ArrayList<>();
-
+
+ private final List completedJobMetrics = new ArrayList<>();
+
/**
- * Gets a list of completed job dates, formatted in milliseconds.
- *
- * @return The completed job dates, formatted in milliseconds.
+ * Gets a list of completed job metrics.
+ *
+ * @return The completed job metrics.
*/
- List getCompletedJobDates() {
- return new ArrayList<>(completedJobDates);
+ List getCompletedJobMetrics() {
+ return new ArrayList<>(completedJobMetrics);
}
-
+
/**
- * Adds a new date to the list of completed job dates.
- *
- * @param date The date to be added.
+ * Adds a new metric to the list of completed job metrics.
+ *
+ * @param completedDate The completed job date.
+ * @param dataSourceSize The data source size.
*/
- void addCompletedJobDate(java.util.Date date) {
- completedJobDates.add(date.getTime());
+ void addCompletedJobMetric(java.util.Date completedDate, long dataSourceSize) {
+ completedJobMetrics.add(new JobMetric(completedDate, dataSourceSize));
}
}
-
+
+ /**
+ * A single job metric for an auto ingest cluster.
+ */
+ static final class JobMetric {
+
+ private final long completedDate;
+ private final long dataSourceSize;
+
+ /**
+ * Instantiates a job metric.
+ *
+ * @param completedDate The job completion date.
+ * @param dataSourceSize The data source size.
+ */
+ JobMetric(java.util.Date completedDate, long dataSourceSize) {
+ this.completedDate = completedDate.getTime();
+ this.dataSourceSize = dataSourceSize;
+ }
+
+ /**
+ * Gets the job completion date, formatted in milliseconds.
+ *
+ * @return The job completion date.
+ */
+ long getCompletedDate() {
+ return completedDate;
+ }
+
+ /**
+ * Gets the data source size.
+ *
+ * @return The data source size.
+ */
+ long getDataSourceSize() {
+ return dataSourceSize;
+ }
+ }
+
/**
* Exception type thrown when there is an error completing an auto ingest
* metrics collector operation.
@@ -157,4 +197,4 @@ final class AutoIngestMetricsCollector {
}
}
-}
\ No newline at end of file
+}
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form
index 49e700ca21..cbe7b53c2f 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.form
@@ -30,10 +30,14 @@
-
-
+
+
-
+
+
+
+
+
@@ -43,17 +47,17 @@
-
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
@@ -109,5 +113,12 @@
+
+
+
+
+
+
+
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java
index 80bcb6958b..af0679be5f 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/AutoIngestMetricsDialog.java
@@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
- * Copyright 2011-2017 Basis Technology Corp.
+ * Copyright 2017 Basis Technology Corp.
* Contact: carrier sleuthkit org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -25,24 +25,28 @@ import java.awt.Window;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.time.ZoneOffset;
+import java.util.List;
import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
+import org.sleuthkit.autopsy.experimental.autoingest.AutoIngestMetricsCollector.JobMetric;
/**
* Displays auto ingest metrics for a cluster.
*/
final class AutoIngestMetricsDialog extends javax.swing.JDialog {
-
+
+ private static final int GIGABYTE_SIZE = 1073741824;
+
private final AutoIngestMetricsCollector autoIngestMetricsCollector;
/**
* Creates an instance of AutoIngestMetricsDialog
- *
+ *
* @param parent The parent container.
*/
@Messages({
"AutoIngestMetricsDialog.title.text=Auto Ingest Cluster Metrics",
- "AutoIngestMetricsDialog.initReportText=Select a date below and click the 'Get Metrics Since...' button to generate\na metrics report."
+ "AutoIngestMetricsDialog.initReportText=Select a date above and click the 'Generate Metrics Report' button to generate\na metrics report."
})
AutoIngestMetricsDialog(Container parent) throws AutoIngestMetricsDialogException {
super((Window) parent, NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.title.text"), ModalityType.MODELESS);
@@ -58,34 +62,39 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog {
setLocationRelativeTo(parent);
setVisible(true);
}
-
+
/**
* Update the metrics shown in the report text area.
*/
private void updateMetrics() {
- if(datePicker.getDate() == null) {
+ if (datePicker.getDate() == null) {
return;
}
-
+
AutoIngestMetricsCollector.MetricsSnapshot metricsSnapshot = autoIngestMetricsCollector.queryCoordinationServiceForMetrics();
- Object[] completedJobDates = metricsSnapshot.getCompletedJobDates().toArray();
- int count = 0;
+ List completedJobMetrics = metricsSnapshot.getCompletedJobMetrics();
+ int jobsCompleted = 0;
+ long dataSourceSizeTotal = 0;
long pickedDate = datePicker.getDate().atStartOfDay().toEpochSecond(ZoneOffset.UTC) * 1000;
- for(int i = completedJobDates.length - 1; i >= 0; i--) {
- if((Long)completedJobDates[i] >= pickedDate) {
- count++;
+
+ for (JobMetric jobMetric : completedJobMetrics) {
+ if (jobMetric.getCompletedDate() >= pickedDate) {
+ jobsCompleted++;
+ dataSourceSizeTotal += jobMetric.getDataSourceSize();
}
}
-
+
SimpleDateFormat dateFormatter = new SimpleDateFormat("MMM d, yyyy");
reportTextArea.setText(String.format(
- "Since %s:\n" +
- "\tNumber of Jobs Completed: %d\n",
+ "Since %s:\n"
+ + "Number of Jobs Completed: %d\n"
+ + "Total Size of Data Sources: %.1f GB\n",
dateFormatter.format(Date.valueOf(datePicker.getDate())),
- count
+ jobsCompleted,
+ (double) dataSourceSizeTotal / GIGABYTE_SIZE
));
}
-
+
/**
* Exception type thrown when there is an error completing an auto ingest
* metrics dialog operation.
@@ -131,6 +140,7 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog {
reportTextArea = new javax.swing.JTextArea();
metricsButton = new javax.swing.JButton();
datePicker = new DatePicker();
+ startingDataLabel = new javax.swing.JLabel();
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
setAlwaysOnTop(true);
@@ -158,6 +168,8 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog {
datePicker.setToolTipText(org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.datePicker.toolTipText")); // NOI18N
+ org.openide.awt.Mnemonics.setLocalizedText(startingDataLabel, org.openide.util.NbBundle.getMessage(AutoIngestMetricsDialog.class, "AutoIngestMetricsDialog.startingDataLabel.text")); // NOI18N
+
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
getContentPane().setLayout(layout);
layout.setHorizontalGroup(
@@ -167,24 +179,28 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1)
.addGroup(layout.createSequentialGroup()
- .addComponent(metricsButton)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
+ .addComponent(startingDataLabel)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
- .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 33, Short.MAX_VALUE)
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 7, Short.MAX_VALUE)
+ .addComponent(metricsButton))
+ .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+ .addGap(0, 0, Short.MAX_VALUE)
.addComponent(closeButton, javax.swing.GroupLayout.PREFERRED_SIZE, 70, javax.swing.GroupLayout.PREFERRED_SIZE)))
.addContainerGap())
);
layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
+ .addGroup(layout.createSequentialGroup()
.addContainerGap()
+ .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
+ .addComponent(metricsButton)
+ .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
+ .addComponent(startingDataLabel))
+ .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 128, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
- .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
- .addComponent(closeButton)
- .addComponent(metricsButton))
- .addComponent(datePicker, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
+ .addComponent(closeButton)
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
);
@@ -208,5 +224,6 @@ final class AutoIngestMetricsDialog extends javax.swing.JDialog {
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JButton metricsButton;
private javax.swing.JTextArea reportTextArea;
+ private javax.swing.JLabel startingDataLabel;
// End of variables declaration//GEN-END:variables
-}
\ No newline at end of file
+}
diff --git a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
index 5f335b1ba4..d953b0ceb3 100755
--- a/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
+++ b/Experimental/src/org/sleuthkit/autopsy/experimental/autoingest/Bundle.properties
@@ -228,10 +228,11 @@ AutoIngestDashboard.prioritizeCaseButton.toolTipText=Move all images associated
AutoIngestDashboard.prioritizeCaseButton.text=Prioritize &Case
AutoIngestMetricsDialog.reportTextArea.text=
AutoIngestDashboard.clusterMetricsButton.text=Cluster Metrics
-AutoIngestMetricsDialog.metricsButton.text=Get Metrics Since...
+AutoIngestMetricsDialog.metricsButton.text=Generate Metrics Report
AutoIngestMetricsDialog.closeButton.text=Close
AutoIngestMetricsDialog.datePicker.toolTipText=Choose a date
ArchiveFilePanel.pathLabel.text=Browse for an archive file:
ArchiveFilePanel.browseButton.text=Browse
ArchiveFilePanel.pathTextField.text=
-ArchiveFilePanel.errorLabel.text=Error Label
\ No newline at end of file
+ArchiveFilePanel.errorLabel.text=Error Label
+AutoIngestMetricsDialog.startingDataLabel.text=Starting Date:
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java
index e116ff171c..cd40efdb55 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/AddTagAction.java
@@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
- *
- * Copyright 2013-16 Basis Technology Corp.
+ *
+ * Copyright 2013-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.
@@ -36,10 +36,12 @@ import javax.swing.SwingWorker;
import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle;
+import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
import org.sleuthkit.autopsy.actions.GetTagNameDialog;
+import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
@@ -48,6 +50,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
+import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskCoreException;
/**
@@ -67,7 +70,8 @@ public class AddTagAction extends Action {
this.selectedFileIDs = selectedFileIDs;
this.tagName = tagName;
setGraphic(controller.getTagsManager().getGraphic(tagName));
- setText(tagName.getDisplayName());
+ String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ setText(tagName.getDisplayName() + notableString);
setEventHandler(actionEvent -> addTagWithComment(""));
}
@@ -78,7 +82,7 @@ public class AddTagAction extends Action {
private void addTagWithComment(String comment) {
addTagsToFiles(tagName, comment, selectedFileIDs);
}
-
+
@NbBundle.Messages({"# {0} - fileID",
"AddDrawableTagAction.addTagsToFiles.alert=Unable to tag file {0}."})
private void addTagsToFiles(TagName tagName, String comment, Set selectedFiles) {
@@ -108,8 +112,8 @@ public class AddTagAction extends Action {
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error tagging file", tskCoreException); //NON-NLS
- Platform.runLater(() ->
- new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show()
+ Platform.runLater(()
+ -> new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show()
);
break;
}
@@ -172,8 +176,8 @@ public class AddTagAction extends Action {
* or select a tag name and adds a tag with the resulting name.
*/
MenuItem newTagMenuItem = new MenuItem(Bundle.AddTagAction_menuItem_newTag());
- newTagMenuItem.setOnAction(actionEvent ->
- SwingUtilities.invokeLater(() -> {
+ newTagMenuItem.setOnAction(actionEvent
+ -> SwingUtilities.invokeLater(() -> {
TagName tagName = GetTagNameDialog.doDialog(getIGWindow());
if (tagName != null) {
new AddTagAction(controller, tagName, selectedFileIDs).handle(actionEvent);
@@ -188,8 +192,8 @@ public class AddTagAction extends Action {
* name.
*/
MenuItem tagAndCommentItem = new MenuItem(Bundle.AddTagAction_menuItem_tagAndComment());
- tagAndCommentItem.setOnAction(actionEvent ->
- SwingUtilities.invokeLater(() -> {
+ tagAndCommentItem.setOnAction(actionEvent
+ -> SwingUtilities.invokeLater(() -> {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(getIGWindow());
if (null != tagNameAndComment) {
new AddTagAction(controller, tagNameAndComment.getTagName(), selectedFileIDs).addTagWithComment(tagNameAndComment.getComment());
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/CategorizeAction.java
index e55078018e..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.datamodel.tags.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 439bb59512..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.datamodel.tags.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 be8c3644bb..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.datamodel.tags.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/actions/DeleteTagAction.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java
index 53a033a2c9..a21d163fdc 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java
@@ -1,15 +1,15 @@
/*
* Autopsy Forensic Browser
- *
+ *
* Copyright 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.
@@ -18,7 +18,6 @@
*/
package org.sleuthkit.autopsy.imagegallery.actions;
-import java.awt.Window;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
@@ -30,24 +29,22 @@ import javafx.scene.control.Alert;
import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem;
import javafx.scene.image.ImageView;
-import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
-import org.openide.windows.TopComponent;
-import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
+import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
-import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
+import org.sleuthkit.datamodel.TskData;
/**
* Instances of this Action allow users to remove tags from content.
@@ -68,7 +65,8 @@ public class DeleteTagAction extends Action {
this.tagName = tagName;
this.contentTag = contentTag;
setGraphic(controller.getTagsManager().getGraphic(tagName));
- setText(tagName.getDisplayName());
+ String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
+ setText(tagName.getDisplayName() + notableString);
setEventHandler(actionEvent -> deleteTag());
}
@@ -84,20 +82,20 @@ public class DeleteTagAction extends Action {
@Override
protected Void doInBackground() throws Exception {
DrawableTagsManager tagsManager = controller.getTagsManager();
-
+
// Pull the from the global context to avoid unnecessary calls
// to the database.
- final Collection selectedFilesList =
- new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
+ final Collection selectedFilesList
+ = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next();
-
+
try {
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
tagsManager.deleteContentTag(contentTag);
} catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS
- Platform.runLater(() ->
- new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show()
+ Platform.runLater(()
+ -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show()
);
}
return null;
@@ -121,25 +119,25 @@ public class DeleteTagAction extends Action {
TagMenu(ImageGalleryController controller) {
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon()));
setText(Bundle.DeleteDrawableTagAction_displayName());
-
+
// For this menu, we shouldn't have more than one file selected.
// Therefore, we will simply grab the first file and work with that.
- final Collection selectedFilesList =
- new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
+ final Collection selectedFilesList
+ = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next();
-
- try {
- List existingTagsList =
- Case.getCurrentCase().getServices().getTagsManager()
- .getContentTagsByContent(file);
- Collection tagNamesList =
- controller.getTagsManager().getNonCategoryTagNames();
+ try {
+ List existingTagsList
+ = Case.getCurrentCase().getServices().getTagsManager()
+ .getContentTagsByContent(file);
+
+ Collection tagNamesList
+ = controller.getTagsManager().getNonCategoryTagNames();
Iterator tagNameIterator = tagNamesList.iterator();
- for(int i=0; tagNameIterator.hasNext(); i++) {
+ for (int i = 0; tagNameIterator.hasNext(); i++) {
TagName tagName = tagNameIterator.next();
- for(ContentTag contentTag : existingTagsList) {
- if(contentTag.getName().getId() == tagName.getId()) {
+ for (ContentTag contentTag : existingTagsList) {
+ if (contentTag.getName().getId() == tagName.getId()) {
DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId());
MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction);
getItems().add(tagNameItem);
@@ -151,7 +149,7 @@ public class DeleteTagAction extends Action {
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
}
- if(getItems().isEmpty()) {
+ if (getItems().isEmpty()) {
setDisable(true);
}
}
diff --git a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java
index 33bc9a58d4..66aa6c578d 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/CategoryManager.java
@@ -35,7 +35,7 @@ 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.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@@ -80,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)
));
@@ -119,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();
@@ -139,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();
}
}
@@ -171,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 {
@@ -188,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));
}
@@ -231,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());
}
@@ -270,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);
}
@@ -285,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);
@@ -301,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 0ac5142f3c..c3b8771b6d 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableAttribute.java
@@ -18,7 +18,7 @@
*/
package org.sleuthkit.autopsy.imagegallery.datamodel;
-import org.sleuthkit.autopsy.datamodel.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
@@ -84,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 5426ac205a..fa008fe3e9 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableDB.java
@@ -18,7 +18,7 @@
*/
package org.sleuthkit.autopsy.imagegallery.datamodel;
-import org.sleuthkit.autopsy.datamodel.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
@@ -231,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();
@@ -1016,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());
}
@@ -1195,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)) {
@@ -1233,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 5b40c9240c..af26dd2e97 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableFile.java
@@ -18,7 +18,7 @@
*/
package org.sleuthkit.autopsy.imagegallery.datamodel;
-import org.sleuthkit.autopsy.datamodel.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import java.lang.ref.SoftReference;
import java.text.MessageFormat;
import java.util.ArrayList;
@@ -85,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;
@@ -216,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;
}
@@ -238,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 0497068924..cb30c37bab 100755
--- a/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java
+++ b/ImageGallery/src/org/sleuthkit/autopsy/imagegallery/datamodel/DrawableTagsManager.java
@@ -18,7 +18,7 @@
*/
package org.sleuthkit.autopsy.imagegallery.datamodel;
-import org.sleuthkit.autopsy.datamodel.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
import com.google.common.eventbus.AsyncEventBus;
import com.google.common.eventbus.EventBus;
import java.util.Collections;
@@ -229,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 e62c2b6541..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.datamodel.tags.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 2841eb5325..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.datamodel.tags.Category;
+import org.sleuthkit.autopsy.datamodel.DhsImageCategory;
/**
* Displays summary statistics (counts) for each group
@@ -44,13 +44,13 @@ import org.sleuthkit.autopsy.datamodel.tags.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 6cb29d46d1..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.datamodel.tags.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