Merge remote-tracking branch 'upstream/develop' into 3245_updateSchema

Conflicts:
	Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/EamDbUtil.java
	Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/PostgresEamDbSettings.java
	Core/src/org/sleuthkit/autopsy/centralrepository/datamodel/SqliteEamDbSettings.java
This commit is contained in:
Ann Priestman 2017-12-01 11:27:19 -05:00
commit d9a40d0bd4
58 changed files with 2523 additions and 1232 deletions

View File

@ -16,6 +16,7 @@
<dependency conf="core->default" org="com.drewnoakes" name="metadata-extractor" rev="2.8.1"/> <dependency conf="core->default" org="com.drewnoakes" name="metadata-extractor" rev="2.8.1"/>
<dependency conf="core->default" org="org.apache.tika" name="tika-core" rev="1.14"/> <dependency conf="core->default" org="org.apache.tika" name="tika-core" rev="1.14"/>
<dependency conf="core->default" org="org.apache.tika" name="tika-parsers" rev="1.14"/>
<dependency conf="core->default" org="com.adobe.xmp" name="xmpcore" rev="5.1.2"/> <dependency conf="core->default" org="com.adobe.xmp" name="xmpcore" rev="5.1.2"/>
<dependency conf="core->default" org="org.apache.zookeeper" name="zookeeper" rev="3.4.6"/> <dependency conf="core->default" org="org.apache.zookeeper" name="zookeeper" rev="3.4.6"/>

View File

@ -1,10 +1,13 @@
file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar 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.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 file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar file.reference.jdom-2.0.5.jar=release/modules/ext/jdom-2.0.5.jar
file.reference.jython-standalone-2.7.0.jar=release/modules/ext/jython-standalone-2.7.0.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.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.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.opencv-248.jar=release/modules/ext/opencv-248.jar
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
@ -13,6 +16,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.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.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-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.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.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 file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
@ -21,12 +25,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 file.reference.zookeeper-3.4.6.jar=release/modules/ext/zookeeper-3.4.6.jar
javac.source=1.8 javac.source=1.8
javac.compilerargs=-Xlint -Xlint:-serial 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 license.file=../LICENSE-2.0.txt
nbm.homepage=http://www.sleuthkit.org/ nbm.homepage=http://www.sleuthkit.org/
nbm.module.author=Brian Carrier nbm.module.author=Brian Carrier
nbm.needs.restart=true 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 source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
spec.version.base=10.9 spec.version.base=10.9

View File

@ -307,7 +307,6 @@
<package>org.sleuthkit.autopsy.datasourceprocessors</package> <package>org.sleuthkit.autopsy.datasourceprocessors</package>
<package>org.sleuthkit.autopsy.directorytree</package> <package>org.sleuthkit.autopsy.directorytree</package>
<package>org.sleuthkit.autopsy.events</package> <package>org.sleuthkit.autopsy.events</package>
<package>org.sleuthkit.autopsy.externalresults</package>
<package>org.sleuthkit.autopsy.filesearch</package> <package>org.sleuthkit.autopsy.filesearch</package>
<package>org.sleuthkit.autopsy.guiutils</package> <package>org.sleuthkit.autopsy.guiutils</package>
<package>org.sleuthkit.autopsy.ingest</package> <package>org.sleuthkit.autopsy.ingest</package>
@ -321,93 +320,25 @@
<package>org.sleuthkit.autopsy.report</package> <package>org.sleuthkit.autopsy.report</package>
<package>org.sleuthkit.datamodel</package> <package>org.sleuthkit.datamodel</package>
</public-packages> </public-packages>
<class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path> <runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin> <binary-origin>release/modules/ext/jdom-2.0.5.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/postgresql-9.4.1211.jre7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/postgresql-9.4.1211.jre7.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/tika-core-1.14.jar</runtime-relative-path> <runtime-relative-path>ext/tika-core-1.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-core-1.14.jar</binary-origin> <binary-origin>release/modules/ext/tika-core-1.14.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.8.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.8.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.8.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path> <runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin> <binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/zookeeper-3.4.6.jar</runtime-relative-path> <runtime-relative-path>ext/opencv-248.jar</runtime-relative-path>
<binary-origin>release/modules/ext/zookeeper-3.4.6.jar</binary-origin> <binary-origin>release/modules/ext/opencv-248.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-recipes-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-recipes-2.8.0.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path> <runtime-relative-path>ext/curator-framework-2.8.0.jar</runtime-relative-path>
@ -417,10 +348,78 @@
<runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path> <runtime-relative-path>ext/commons-dbcp2-2.1.1.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin> <binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/tika-parsers-1.14.jar</runtime-relative-path>
<binary-origin>release/modules/ext/tika-parsers-1.14.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jython-standalone-2.7.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jython-standalone-2.7.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/mchange-commons-java-0.2.9.jar</runtime-relative-path>
<binary-origin>release/modules/ext/mchange-commons-java-0.2.9.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/postgresql-9.4.1211.jre7.jar</runtime-relative-path>
<binary-origin>release/modules/ext/postgresql-9.4.1211.jre7.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-recipes-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-recipes-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/xmpcore-5.1.2.jar</runtime-relative-path>
<binary-origin>release/modules/ext/xmpcore-5.1.2.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/StixLib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/StixLib.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/curator-client-2.8.0.jar</runtime-relative-path>
<binary-origin>release/modules/ext/curator-client-2.8.0.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sqlite-jdbc-3.8.11.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sqlite-jdbc-3.8.11.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/activemq-all-5.11.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/activemq-all-5.11.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/Rejistry-1.0-SNAPSHOT.jar</runtime-relative-path>
<binary-origin>release/modules/ext/Rejistry-1.0-SNAPSHOT.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/sevenzipjbinding-AllPlatforms.jar</runtime-relative-path>
<binary-origin>release/modules/ext/sevenzipjbinding-AllPlatforms.jar</binary-origin>
</class-path-extension>
<class-path-extension> <class-path-extension>
<runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path> <runtime-relative-path>ext/commons-pool2-2.4.2.jar</runtime-relative-path>
<binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin> <binary-origin>release\modules\ext\commons-pool2-2.4.2.jar</binary-origin>
</class-path-extension> </class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/metadata-extractor-2.9.1.jar</runtime-relative-path>
<binary-origin>release/modules/ext/metadata-extractor-2.9.1.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/commons-compress-1.12.jar</runtime-relative-path>
<binary-origin>release/modules/ext/commons-compress-1.12.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/jdom-2.0.5-contrib.jar</runtime-relative-path>
<binary-origin>release/modules/ext/jdom-2.0.5-contrib.jar</binary-origin>
</class-path-extension>
<class-path-extension>
<runtime-relative-path>ext/c3p0-0.9.5.jar</runtime-relative-path>
<binary-origin>release/modules/ext/c3p0-0.9.5.jar</binary-origin>
</class-path-extension>
</data> </data>
</configuration> </configuration>
</project> </project>

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * 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.JMenu;
import javax.swing.JMenuItem; import javax.swing.JMenuItem;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.actions.Presenter; import org.openide.util.actions.Presenter;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* An abstract base class for Actions that allow users to tag SleuthKit data * 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()) { if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) { for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey(); 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 // for the bookmark tag name only, added shortcut label
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) { if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT); 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")); JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags"));
empty.setEnabled(false); empty.setEnabled(false);
quickTagMenu.add(empty); quickTagMenu.add(empty);
} }
quickTagMenu.addSeparator(); 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 * 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 * display name to be added to the menu with an action listener without
* having to instantiate a TagName object for it. * having to instantiate a TagName object for it. When the method is
* When the method is called, the TagName object is created here if it * called, the TagName object is created here if it doesn't already
* doesn't already exist. * exist.
* *
* @param tagDisplayName display name for the tag name * @param tagDisplayName display name for the tag name
* @param tagName TagName object associated with the tag name, * @param tagName TagName object associated with the tag name,
* may be null * may be null

View File

@ -4,7 +4,7 @@ GetTagNameDialog.okButton.text=OK
GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names: GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names:
GetTagNameDialog.newTagPanel.border.title=New Tag GetTagNameDialog.newTagPanel.border.title=New Tag
GetTagNameDialog.tagNameLabel.text=Tag Name: GetTagNameDialog.tagNameLabel.text=Tag Name:
GetTagNameAndCommentDialog.newTagButton.text=New Tag Name GetTagNameAndCommentDialog.newTagButton.text=New Tag
GetTagNameAndCommentDialog.okButton.text=OK GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
GetTagNameAndCommentDialog.commentText.text= GetTagNameAndCommentDialog.commentText.text=
@ -12,7 +12,6 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment:
# To change this template, choose Tools | Templates # To change this template, choose Tools | Templates
# and open the template in the editor. # and open the template in the editor.
GetTagNameAndCommentDialog.cancelButton.text=Cancel GetTagNameAndCommentDialog.cancelButton.text=Cancel
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
GetTagNameAndCommentDialog.tagLabel.text=Tag: GetTagNameAndCommentDialog.tagLabel.text=Tag:
AddTagAction.bookmarkFile=Bookmark file AddTagAction.bookmarkFile=Bookmark file
AddTagAction.quickTag=Quick Tag AddTagAction.quickTag=Quick Tag
@ -45,3 +44,4 @@ ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
OpenPythonModulesFolderAction.actionName.text=Python Plugins OpenPythonModulesFolderAction.actionName.text=Python Plugins
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0} OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}
CTL_OpenPythonModulesFolderAction=Python Plugins CTL_OpenPythonModulesFolderAction=Python Plugins
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use

View File

@ -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.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.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a
GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb 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 GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a
AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0 AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
AddBlackboardArtifactTagAction.pluralTagResult=\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.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 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\\ \: * ? " < > | 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 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

View File

@ -1,15 +1,15 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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.BlackboardArtifactTag;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Instances of this Action allow users to delete tags applied to blackboard * 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" "DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag"
}) })
public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup { public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup {
private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName()); private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName());
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -89,27 +90,27 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
} }
@NbBundle.Messages({"# {0} - artifactID", @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) { protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) {
new SwingWorker<Void, Void>() { new SwingWorker<Void, Void>() {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
// Pull the from the global context to avoid unnecessary calls // Pull the from the global context to avoid unnecessary calls
// to the database. // to the database.
final Collection<AbstractFile> selectedFilesList = final Collection<AbstractFile> selectedFilesList
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next(); AbstractFile file = selectedFilesList.iterator().next();
try { try {
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
tagsManager.deleteBlackboardArtifactTag(artifactTag); tagsManager.deleteBlackboardArtifactTag(artifactTag);
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS
Platform.runLater(() -> Platform.runLater(()
new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show() -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show()
); );
} }
return null; return null;
@ -133,21 +134,21 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
* comment. * comment.
*/ */
@NbBundle.Messages({"# {0} - artifactID", @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 class TagMenu extends JMenu {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
TagMenu() { TagMenu() {
super(getActionDisplayName()); super(getActionDisplayName());
final Collection<BlackboardArtifact> selectedBlackboardArtifactsList = final Collection<BlackboardArtifact> selectedBlackboardArtifactsList
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
if(!selectedBlackboardArtifactsList.isEmpty()) { if (!selectedBlackboardArtifactsList.isEmpty()) {
BlackboardArtifact artifact = BlackboardArtifact artifact
selectedBlackboardArtifactsList.iterator().next(); = selectedBlackboardArtifactsList.iterator().next();
// Get the current set of tag names. // Get the current set of tag names.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
@ -163,17 +164,18 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
// a tag with the associated tag name. // a tag with the associated tag name.
if (null != tagNamesMap && !tagNamesMap.isEmpty()) { if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
try { try {
List<BlackboardArtifactTag> existingTagsList = List<BlackboardArtifactTag> existingTagsList
Case.getCurrentCase().getServices().getTagsManager() = Case.getCurrentCase().getServices().getTagsManager()
.getBlackboardArtifactTagsByArtifact(artifact); .getBlackboardArtifactTagsByArtifact(artifact);
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) { for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
String tagDisplayName = entry.getKey(); String tagDisplayName = entry.getKey();
TagName tagName = entry.getValue(); TagName tagName = entry.getValue();
for(BlackboardArtifactTag artifactTag : existingTagsList) { for (BlackboardArtifactTag artifactTag : existingTagsList) {
if(tagDisplayName.equals(artifactTag.getName().getDisplayName())) { if (tagDisplayName.equals(artifactTag.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) -> { tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, artifactTag, artifact.getArtifactID()); deleteTag(tagName, artifactTag, artifact.getArtifactID());
}); });
@ -187,7 +189,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
} }
} }
if(getItemCount() == 0) { if (getItemCount() == 0) {
setEnabled(false); setEnabled(false);
} }
} }

View File

@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Instances of this Action allow users to delete tags applied to content. * 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(); TagName tagName = entry.getValue();
for(ContentTag contentTag : existingTagsList) { for(ContentTag contentTag : existingTagsList) {
if(tagDisplayName.equals(contentTag.getName().getDisplayName())) { 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) -> { tagNameItem.addActionListener((ActionEvent e) -> {
deleteTag(tagName, contentTag, file.getId()); deleteTag(tagName, contentTag, file.getId());
}); });

View File

@ -28,7 +28,7 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="newTagButton" min="-2" max="-2" attributes="0"/> <Component id="newTagButton" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="48" max="32767" attributes="0"/> <EmptySpace pref="165" max="32767" attributes="0"/>
<Component id="okButton" linkSize="1" min="-2" pref="67" max="-2" attributes="0"/> <Component id="okButton" linkSize="1" min="-2" pref="67" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
@ -39,11 +39,10 @@
<Component id="tagLabel" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="tagLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" max="-2" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="commentText" max="32767" attributes="0"/> <Component id="commentText" max="32767" attributes="0"/>
<Component id="tagCombo" pref="214" max="32767" attributes="0"/> <Component id="tagCombo" max="32767" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -108,8 +107,8 @@
</Property> </Property>
</Properties> </Properties>
<AuxValues> <AuxValues>
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox&lt;String&gt;()"/> <AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox&lt;TagName&gt;()"/>
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;String&gt;"/> <AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="&lt;TagName&gt;"/>
</AuxValues> </AuxValues>
</Component> </Component>
<Component class="javax.swing.JLabel" name="tagLabel"> <Component class="javax.swing.JLabel" name="tagLabel">

View File

@ -1,15 +1,15 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,17 +18,20 @@
*/ */
package org.sleuthkit.autopsy.actions; package org.sleuthkit.autopsy.actions;
import java.awt.Component;
import java.awt.Window; import java.awt.Window;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.Map;
import java.util.TreeMap;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.HashSet;
import java.util.Set;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.DefaultListCellRenderer;
import javax.swing.InputMap; import javax.swing.InputMap;
import javax.swing.JComponent; import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JList;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; 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.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
public class GetTagNameAndCommentDialog extends JDialog { public class GetTagNameAndCommentDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class, private final Set<TagName> tagNamesSet = new HashSet<>();
"GetTagNameAndCommentDialog.noTags");
private final Map<String, TagName> tagNamesMap = new TreeMap<>();
private TagNameAndComment tagNameAndComment = null; private TagNameAndComment tagNameAndComment = null;
public static class TagNameAndComment { public static class TagNameAndComment {
private final TagName tagName; private final TagName tagName;
@ -68,7 +70,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
/** /**
* Show the Tag Name and Comment Dialog and return the TagNameAndContent * Show the Tag Name and Comment Dialog and return the TagNameAndContent
* chosen by the user. The dialog will be centered with the main autopsy * 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 * @return a TagNameAndComment instance containing the TagName selected by
* the user and the entered comment, or null if the user canceled * the user and the entered comment, or null if the user canceled
@ -102,21 +104,34 @@ public class GetTagNameAndCommentDialog extends JDialog {
ModalityType.APPLICATION_MODAL); ModalityType.APPLICATION_MODAL);
} }
private void display() { private void display() {
initComponents(); 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. // Set up the dialog to close when Esc is pressed.
String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameAndCommentDialog.cancelName"); String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameAndCommentDialog.cancelName");
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap(); ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() { actionMap.put(cancelName, new AbstractAction() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
dispose(); dispose();
} }
}); }
);
// Populate the combo box with the available tag names and save the // Populate the combo box with the available tag names and save the
// tag name DTOs to be enable to return the one the user selects. // tag name DTOs to be enable to return the one the user selects.
@ -124,23 +139,22 @@ public class GetTagNameAndCommentDialog extends JDialog {
// not exist in the database). // not exist in the database).
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager(); TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
try { try {
tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap()); tagNamesSet.addAll(tagsManager.getAllTagNames());
} catch (TskCoreException ex) { } 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()) { for (TagName tag : tagNamesSet) {
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
} else { tagCombo.addItem(tag);
for (String tagDisplayName : tagNamesMap.keySet()) {
tagCombo.addItem(tagDisplayName);
}
} }
// Center and show the dialog box. // Center and show the dialog box.
this.setLocationRelativeTo(this.getOwner()); this.setLocationRelativeTo(this.getOwner());
setVisible(true); setVisible(true);
} }
/** /**
* This method is called from within the constructor to initialize the form. * 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 * 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(); okButton = new javax.swing.JButton();
cancelButton = new javax.swing.JButton(); cancelButton = new javax.swing.JButton();
tagCombo = new javax.swing.JComboBox<String>(); tagCombo = new javax.swing.JComboBox<TagName>();
tagLabel = new javax.swing.JLabel(); tagLabel = new javax.swing.JLabel();
commentLabel = new javax.swing.JLabel(); commentLabel = new javax.swing.JLabel();
commentText = new javax.swing.JTextField(); commentText = new javax.swing.JTextField();
@ -203,7 +217,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addComponent(newTagButton) .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) .addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)) .addComponent(cancelButton))
@ -212,10 +226,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
.addComponent(commentLabel) .addComponent(commentLabel)
.addComponent(tagLabel)) .addComponent(tagLabel))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .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(commentText)
.addComponent(tagCombo, 0, 214, Short.MAX_VALUE)) .addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap()) .addContainerGap())
); );
@ -246,21 +259,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String tagDisplayName = (String) tagCombo.getSelectedItem(); TagName tagNameFromCombo = (TagName) 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
}
}
tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText()); tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText());
dispose(); dispose();
}//GEN-LAST:event_okButtonActionPerformed }//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 private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
TagName newTagName = GetTagNameDialog.doDialog(this); TagName newTagName = GetTagNameDialog.doDialog(this);
if (newTagName != null) { if (newTagName != null) {
tagNamesMap.put(newTagName.getDisplayName(), newTagName); tagNamesSet.add(newTagName);
tagCombo.addItem(newTagName.getDisplayName()); tagCombo.addItem(newTagName);
tagCombo.setSelectedItem(newTagName.getDisplayName()); tagCombo.setSelectedItem(newTagName);
} }
}//GEN-LAST:event_newTagButtonActionPerformed }//GEN-LAST:event_newTagButtonActionPerformed
@ -290,7 +289,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
private javax.swing.JTextField commentText; private javax.swing.JTextField commentText;
private javax.swing.JButton newTagButton; private javax.swing.JButton newTagButton;
private javax.swing.JButton okButton; private javax.swing.JButton okButton;
private javax.swing.JComboBox<String> tagCombo; private javax.swing.JComboBox<TagName> tagCombo;
private javax.swing.JLabel tagLabel; private javax.swing.JLabel tagLabel;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
} }

View File

@ -142,11 +142,20 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="tagNameLabel" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/> <Component id="descriptionScrollPane" alignment="1" max="32767" attributes="0"/>
<Component id="tagNameField" pref="235" max="32767" attributes="0"/> <Component id="tagNameField" pref="323" max="32767" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="notableCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="descriptionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="tagNameLabel" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
@ -154,12 +163,17 @@
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace min="-2" pref="6" max="-2" attributes="0"/>
<Component id="tagNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Component id="tagNameField" min="-2" max="-2" attributes="0"/>
<Component id="tagNameLabel" alignment="3" min="-2" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="tagNameField" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
</Group> <EmptySpace max="-2" attributes="0"/>
<EmptySpace pref="164" max="32767" attributes="0"/> <Component id="descriptionScrollPane" min="-2" pref="57" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="notableCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="31" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
@ -182,6 +196,38 @@
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="tagNameFieldKeyReleased"/> <EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="tagNameFieldKeyReleased"/>
</Events> </Events>
</Component> </Component>
<Component class="javax.swing.JLabel" name="descriptionLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.descriptionLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Container class="javax.swing.JScrollPane" name="descriptionScrollPane">
<AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents>
<Component class="javax.swing.JTextArea" name="descriptionTextArea">
<Properties>
<Property name="columns" type="int" value="20"/>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/>
</Property>
<Property name="rows" type="int" value="3"/>
</Properties>
</Component>
</SubComponents>
</Container>
<Component class="javax.swing.JCheckBox" name="notableCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.notableCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>

View File

@ -1,15 +1,15 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2016 Basis Technology Corp. * Copyright 2011-2016 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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 javax.swing.table.AbstractTableModel;
import org.openide.util.ImageUtilities; import org.openide.util.ImageUtilities;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager; import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; 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 { public class GetTagNameDialog extends JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -79,7 +83,7 @@ public class GetTagNameDialog extends JDialog {
} }
private GetTagNameDialog(Window owner) { private GetTagNameDialog(Window owner) {
super(owner, super(owner,
NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"), NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"),
ModalityType.APPLICATION_MODAL); ModalityType.APPLICATION_MODAL);
} }
@ -95,7 +99,7 @@ public class GetTagNameDialog extends JDialog {
ActionMap actionMap = getRootPane().getActionMap(); ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() { actionMap.put(cancelName, new AbstractAction() {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@Override @Override
public void actionPerformed(ActionEvent e) { public void actionPerformed(ActionEvent e) {
cancelButtonActionPerformed(e); cancelButtonActionPerformed(e);
@ -120,9 +124,9 @@ public class GetTagNameDialog extends JDialog {
// Center and show the dialog box. // Center and show the dialog box.
this.setLocationRelativeTo(this.getOwner()); this.setLocationRelativeTo(this.getOwner());
setVisible(true); setVisible(true);
} }
private class TagsTableModel extends AbstractTableModel { private class TagsTableModel extends AbstractTableModel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -172,6 +176,10 @@ public class GetTagNameDialog extends JDialog {
newTagPanel = new javax.swing.JPanel(); newTagPanel = new javax.swing.JPanel();
tagNameLabel = new javax.swing.JLabel(); tagNameLabel = new javax.swing.JLabel();
tagNameField = new javax.swing.JTextField(); 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); setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
addKeyListener(new java.awt.event.KeyAdapter() { 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); javax.swing.GroupLayout newTagPanelLayout = new javax.swing.GroupLayout(newTagPanel);
newTagPanel.setLayout(newTagPanelLayout); newTagPanel.setLayout(newTagPanelLayout);
newTagPanelLayout.setHorizontalGroup( newTagPanelLayout.setHorizontalGroup(
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newTagPanelLayout.createSequentialGroup() .addGroup(newTagPanelLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(tagNameLabel) .addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(36, 36, 36) .addComponent(descriptionScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 235, Short.MAX_VALUE) .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()) .addContainerGap())
); );
newTagPanelLayout.setVerticalGroup( newTagPanelLayout.setVerticalGroup(
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(newTagPanelLayout.createSequentialGroup() .addGroup(newTagPanelLayout.createSequentialGroup()
.addContainerGap() .addGap(6, 6, 6)
.addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(tagNameLabel)
.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)) .addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addContainerGap(164, Short.MAX_VALUE)) .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()); javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
@ -288,8 +317,14 @@ public class GetTagNameDialog extends JDialog {
dispose(); dispose();
}//GEN-LAST:event_cancelButtonActionPerformed }//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 private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String tagDisplayName = tagNameField.getText(); String tagDisplayName = tagNameField.getText();
String userTagDescription = descriptionTextArea.getText();
TskData.FileKnown status = notableCheckbox.isSelected() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
if (tagDisplayName.isEmpty()) { if (tagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(), 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.illegalChars.msg"),
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"), NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"),
JOptionPane.ERROR_MESSAGE); 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 { } else {
tagName = tagNamesMap.get(tagDisplayName); tagName = tagNamesMap.get(tagDisplayName);
if (tagName == null) { if (tagName == null) {
try { try {
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName); tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName, userTagDescription, TagName.HTML_COLOR.NONE, status);
dispose(); dispose();
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
@ -331,7 +373,10 @@ public class GetTagNameDialog extends JDialog {
} }
} }
} else { } 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 }//GEN-LAST:event_okButtonActionPerformed
@ -350,8 +395,12 @@ public class GetTagNameDialog extends JDialog {
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JButton cancelButton; 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.JScrollPane jScrollPane1;
private javax.swing.JPanel newTagPanel; private javax.swing.JPanel newTagPanel;
private javax.swing.JCheckBox notableCheckbox;
private javax.swing.JButton okButton; private javax.swing.JButton okButton;
private javax.swing.JLabel preexistingLabel; private javax.swing.JLabel preexistingLabel;
private javax.swing.JTextField tagNameField; private javax.swing.JTextField tagNameField;

View File

@ -362,7 +362,14 @@ public class Case {
* case number, the examiner name, examiner phone, examiner email, and * case number, the examiner name, examiner phone, examiner email, and
* the case notes. * 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;
}; };
/** /**
@ -1472,6 +1479,18 @@ public class Case {
eventPublisher.publish(new ContentTagDeletedEvent(deletedTag)); 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. * Notifies case event subscribers that an artifact tag has been added.
* *

View File

@ -9,15 +9,7 @@ TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name
TagOptionsPanel.tagTypesListLabel.text=Tag Names: TagOptionsPanel.tagTypesListLabel.text=Tag Names:
TagOptionsPanel.deleteTagNameButton.text=Delete Tag TagOptionsPanel.deleteTagNameButton.text=Delete Tag
TagOptionsPanel.newTagNameButton.text=New Tag TagOptionsPanel.newTagNameButton.text=New Tag
TagOptionsPanel.editTagNameButton.text=Edit Tag
TagNameDialog.descriptionLabel.text=Description:
TagNameDialog.okButton.text=OK TagNameDialog.okButton.text=OK
TagNameDialog.cancelButton.text=Cancel TagNameDialog.cancelButton.text=Cancel
TagNameDialog.tagNameTextField.text= TagNameDialog.tagNameTextField.text=
TagNameDialog.newTagNameLabel.text=Name: TagNameDialog.newTagNameLabel.text=Name:
TagNameDialog.notableCheckbox.text=Tag indicates item is notable.
TagOptionsPanel.isNotableLabel.text=Tag indicates item is notable:
TagOptionsPanel.notableYesOrNoLabel.text=
TagOptionsPanel.descriptionLabel.text=Tag Description:
TagOptionsPanel.jTextArea1.text=Create and manage tags, which can be applied to files and results in the case. Notable tags will cause items tagged with them to be flagged as notable when using a central repository.
TagOptionsPanel.ingestRunningWarningLabel.text=Cannot make changes to existing tags when ingest is running!

View File

@ -66,7 +66,7 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
* @param displayName The display name for the tag name. * @param displayName The display name for the tag name.
* @param description The description for the tag name. * @param description The description for the tag name.
* @param color The color for the tag name. * @param color The color for the tag name.
* @param knownStatus The status denoted by the tag name. * @param status The status denoted by the tag name.
*/ */
TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) { TagNameDefinition(String displayName, String description, TagName.HTML_COLOR color, TskData.FileKnown status) {
this.displayName = displayName; this.displayName = displayName;
@ -107,13 +107,12 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
} }
/** /**
* Whether or not the status that this tag implies Notable status * The status which will be applied to items with this tag.
* *
* @return true if the Notable status is implied by this tag, false * @return a value of TskData.FileKnown which is associated with this tag
* otherwise.
*/ */
boolean isNotable() { TskData.FileKnown getKnownStatus() {
return knownStatus == TskData.FileKnown.BAD; return knownStatus;
} }
/** /**
@ -157,8 +156,9 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
if (!(obj instanceof TagNameDefinition)) { if (!(obj instanceof TagNameDefinition)) {
return false; return false;
} }
TagNameDefinition thatTagName = (TagNameDefinition) obj; boolean sameName = this.getDisplayName().equals(((TagNameDefinition) obj).getDisplayName());
return this.getDisplayName().equals(thatTagName.getDisplayName()); boolean sameStatus = this.getKnownStatus().equals(((TagNameDefinition) obj).getKnownStatus());
return sameName && sameStatus;
} }
/** /**

View File

@ -117,7 +117,7 @@
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor"> <Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="0"/> <Font name="Tahoma" size="11" style="0"/>
</Property> </Property>
<Property name="rows" type="int" value="5"/> <Property name="rows" type="int" value="3"/>
</Properties> </Properties>
</Component> </Component>
</SubComponents> </SubComponents>

View File

@ -1,20 +1,20 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.casemodule.services; package org.sleuthkit.autopsy.casemodule.services;
@ -29,7 +29,10 @@ import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener; import javax.swing.event.DocumentListener;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.sleuthkit.datamodel.TskData;
@Messages({"TagNameDialog.descriptionLabel.text=Description:",
"TagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
final class TagNameDialog extends javax.swing.JDialog { final class TagNameDialog extends javax.swing.JDialog {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
@ -59,7 +62,7 @@ final class TagNameDialog extends javax.swing.JDialog {
initComponents(); initComponents();
tagNameTextField.setText(tagNameToEdit.getDisplayName()); tagNameTextField.setText(tagNameToEdit.getDisplayName());
descriptionTextArea.setText(tagNameToEdit.getDescription()); descriptionTextArea.setText(tagNameToEdit.getDescription());
notableCheckbox.setSelected(tagNameToEdit.isNotable()); notableCheckbox.setSelected(tagNameToEdit.getKnownStatus() == TskData.FileKnown.BAD);
tagNameTextField.setEnabled(false); tagNameTextField.setEnabled(false);
this.display(); this.display();
} }
@ -126,24 +129,35 @@ final class TagNameDialog extends javax.swing.JDialog {
* *
* @param okPressed whether the OK button was pressed. * @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) { private void doButtonAction(boolean okPressed) {
if (okPressed) { if (okPressed) {
String newTagDisplayName = tagNameTextField.getText().trim(); String newTagDisplayName = tagNameTextField.getText().trim();
String descriptionText = descriptionTextArea.getText();
if (newTagDisplayName.isEmpty()) { if (newTagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.message"), NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.message"),
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.title"), NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.title"),
JOptionPane.ERROR_MESSAGE); JOptionPane.ERROR_MESSAGE);
return; return;
} }
//if a tag name contains illegal characters and is not the name of one of the standard tags //if a tag name contains illegal characters and is not the name of one of the standard tags
if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefinition.getStandardTagNames().contains(newTagDisplayName)) { if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefinition.getStandardTagNames().contains(newTagDisplayName)) {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.message"), NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"),
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.title"), 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); JOptionPane.ERROR_MESSAGE);
return; return;
} }
userTagDescription = descriptionTextArea.getText(); userTagDescription = descriptionTextArea.getText();
userTagDisplayName = newTagDisplayName; userTagDisplayName = newTagDisplayName;
userTagIsNotable = notableCheckbox.isSelected(); userTagIsNotable = notableCheckbox.isSelected();
@ -230,7 +244,7 @@ final class TagNameDialog extends javax.swing.JDialog {
descriptionTextArea.setColumns(20); descriptionTextArea.setColumns(20);
descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
descriptionTextArea.setRows(5); descriptionTextArea.setRows(3);
descriptionScrollPane.setViewportView(descriptionTextArea); 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(descriptionLabel, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.descriptionLabel.text")); // NOI18N

View File

@ -91,7 +91,7 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="103" groupAlignment="1" max="-2" attributes="0"> <Group type="103" groupAlignment="1" max="-2" attributes="0">
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/> <Component id="TagNameScrollPane" alignment="0" max="32767" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="newTagNameButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="newTagNameButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
@ -100,7 +100,7 @@
<Component id="deleteTagNameButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="deleteTagNameButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<Component id="jScrollPane3" alignment="0" min="-2" pref="345" max="-2" attributes="0"/> <Component id="panelDescriptionScrollPane" alignment="0" min="-2" pref="345" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group> </Group>
@ -113,11 +113,11 @@
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/> <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="jScrollPane3" min="-2" max="-2" attributes="0"/> <Component id="panelDescriptionScrollPane" min="-2" pref="65" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="tagTypesListLabel" min="-2" max="-2" attributes="0"/> <Component id="tagTypesListLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="jScrollPane1" pref="355" max="32767" attributes="0"/> <Component id="TagNameScrollPane" pref="338" max="32767" attributes="0"/>
<EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/> <EmptySpace type="unrelated" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="newTagNameButton" linkSize="2" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="newTagNameButton" linkSize="2" alignment="3" min="-2" max="-2" attributes="0"/>
@ -137,7 +137,7 @@
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane1"> <Container class="javax.swing.JScrollPane" name="TagNameScrollPane">
<AuxValues> <AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues> </AuxValues>
@ -223,14 +223,14 @@
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editTagNameButtonActionPerformed"/> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="editTagNameButtonActionPerformed"/>
</Events> </Events>
</Component> </Component>
<Container class="javax.swing.JScrollPane" name="jScrollPane3"> <Container class="javax.swing.JScrollPane" name="panelDescriptionScrollPane">
<AuxValues> <AuxValues>
<AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/> <AuxValue name="autoScrollPane" type="java.lang.Boolean" value="true"/>
</AuxValues> </AuxValues>
<Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/> <Layout class="org.netbeans.modules.form.compat2.layouts.support.JScrollPaneSupportLayout"/>
<SubComponents> <SubComponents>
<Component class="javax.swing.JTextArea" name="jTextArea1"> <Component class="javax.swing.JTextArea" name="panelDescriptionTextArea">
<Properties> <Properties>
<Property name="editable" type="boolean" value="false"/> <Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> <Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
@ -243,7 +243,7 @@
<Property name="lineWrap" type="boolean" value="true"/> <Property name="lineWrap" type="boolean" value="true"/>
<Property name="rows" type="int" value="3"/> <Property name="rows" type="int" value="3"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.jTextArea1.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/casemodule/services/Bundle.properties" key="TagOptionsPanel.panelDescriptionTextArea.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="wrapStyleWord" type="boolean" value="true"/> <Property name="wrapStyleWord" type="boolean" value="true"/>
<Property name="focusable" type="boolean" value="false"/> <Property name="focusable" type="boolean" value="false"/>

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule.services;
import java.awt.EventQueue; import java.awt.EventQueue;
import java.beans.PropertyChangeEvent; import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.util.HashSet;
import java.util.Set; import java.util.Set;
import java.util.TreeSet; import java.util.TreeSet;
import javax.swing.DefaultListModel; import javax.swing.DefaultListModel;
@ -28,6 +29,8 @@ import javax.swing.JOptionPane;
import javax.swing.event.ListSelectionEvent; import javax.swing.event.ListSelectionEvent;
import org.netbeans.spi.options.OptionsPanelController; import org.netbeans.spi.options.OptionsPanelController;
import org.openide.util.NbBundle; 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.corecomponents.OptionsPanel;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
@ -39,22 +42,33 @@ import org.sleuthkit.datamodel.TskData;
final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel { final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
private static final long serialVersionUID = 1L; 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 static final TagName.HTML_COLOR DEFAULT_COLOR = TagName.HTML_COLOR.NONE;
private final DefaultListModel<TagNameDefinition> tagTypesListModel; private final DefaultListModel<TagNameDefinition> tagTypesListModel;
private Set<TagNameDefinition> tagTypes; private Set<TagNameDefinition> tagTypes;
private IngestJobEventPropertyChangeListener ingestJobEventsListener; private IngestJobEventPropertyChangeListener ingestJobEventsListener;
private Set<String> updatedStatusTags;
/** /**
* Creates new form TagsManagerOptionsPanel * Creates new form TagOptionsPanel
*/ */
TagOptionsPanel() { TagOptionsPanel() {
tagTypesListModel = new DefaultListModel<>(); tagTypesListModel = new DefaultListModel<>();
tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions()); tagTypes = new TreeSet<>(TagNameDefinition.getTagNameDefinitions());
updatedStatusTags = new HashSet<>();
initComponents(); initComponents();
customizeComponents(); 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() { private void customizeComponents() {
tagNamesList.setModel(tagTypesListModel); tagNamesList.setModel(tagTypesListModel);
tagNamesList.addListSelectionListener((ListSelectionEvent event) -> { tagNamesList.addListSelectionListener((ListSelectionEvent event) -> {
@ -88,13 +102,13 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
jSplitPane1 = new javax.swing.JSplitPane(); jSplitPane1 = new javax.swing.JSplitPane();
modifyTagTypesListPanel = new javax.swing.JPanel(); modifyTagTypesListPanel = new javax.swing.JPanel();
tagTypesListLabel = new javax.swing.JLabel(); tagTypesListLabel = new javax.swing.JLabel();
jScrollPane1 = new javax.swing.JScrollPane(); TagNameScrollPane = new javax.swing.JScrollPane();
tagNamesList = new javax.swing.JList<>(); tagNamesList = new javax.swing.JList<>();
newTagNameButton = new javax.swing.JButton(); newTagNameButton = new javax.swing.JButton();
deleteTagNameButton = new javax.swing.JButton(); deleteTagNameButton = new javax.swing.JButton();
editTagNameButton = new javax.swing.JButton(); editTagNameButton = new javax.swing.JButton();
jScrollPane3 = new javax.swing.JScrollPane(); panelDescriptionScrollPane = new javax.swing.JScrollPane();
jTextArea1 = new javax.swing.JTextArea(); panelDescriptionTextArea = new javax.swing.JTextArea();
tagTypesAdditionalPanel = new javax.swing.JPanel(); tagTypesAdditionalPanel = new javax.swing.JPanel();
descriptionLabel = new javax.swing.JLabel(); descriptionLabel = new javax.swing.JLabel();
descriptionScrollPane = new javax.swing.JScrollPane(); descriptionScrollPane = new javax.swing.JScrollPane();
@ -114,7 +128,7 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.tagTypesListLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(tagTypesListLabel, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.tagTypesListLabel.text")); // NOI18N
tagNamesList.setSelectionMode(javax.swing.ListSelectionModel.SINGLE_SELECTION); 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 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 org.openide.awt.Mnemonics.setLocalizedText(newTagNameButton, org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.newTagNameButton.text")); // NOI18N
@ -149,16 +163,16 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
} }
}); });
jTextArea1.setEditable(false); panelDescriptionTextArea.setEditable(false);
jTextArea1.setBackground(new java.awt.Color(240, 240, 240)); panelDescriptionTextArea.setBackground(new java.awt.Color(240, 240, 240));
jTextArea1.setColumns(20); panelDescriptionTextArea.setColumns(20);
jTextArea1.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N panelDescriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
jTextArea1.setLineWrap(true); panelDescriptionTextArea.setLineWrap(true);
jTextArea1.setRows(3); panelDescriptionTextArea.setRows(3);
jTextArea1.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.jTextArea1.text")); // NOI18N panelDescriptionTextArea.setText(org.openide.util.NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.panelDescriptionTextArea.text")); // NOI18N
jTextArea1.setWrapStyleWord(true); panelDescriptionTextArea.setWrapStyleWord(true);
jTextArea1.setFocusable(false); panelDescriptionTextArea.setFocusable(false);
jScrollPane3.setViewportView(jTextArea1); panelDescriptionScrollPane.setViewportView(panelDescriptionTextArea);
javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel); javax.swing.GroupLayout modifyTagTypesListPanelLayout = new javax.swing.GroupLayout(modifyTagTypesListPanel);
modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout); modifyTagTypesListPanel.setLayout(modifyTagTypesListPanelLayout);
@ -171,14 +185,14 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false) .addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING, false)
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.LEADING) .addComponent(TagNameScrollPane, javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, modifyTagTypesListPanelLayout.createSequentialGroup() .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) .addComponent(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(editTagNameButton, 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)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(deleteTagNameButton, 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)))
.addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 345, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGap(0, 0, Short.MAX_VALUE))) .addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap()) .addContainerGap())
); );
@ -189,11 +203,11 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(modifyTagTypesListPanelLayout.createSequentialGroup() .addGroup(modifyTagTypesListPanelLayout.createSequentialGroup()
.addGap(10, 10, 10) .addGap(10, 10, 10)
.addComponent(jScrollPane3, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(panelDescriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 65, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(tagTypesListLabel) .addComponent(tagTypesListLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 355, Short.MAX_VALUE) .addComponent(TagNameScrollPane, javax.swing.GroupLayout.DEFAULT_SIZE, 338, Short.MAX_VALUE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(modifyTagTypesListPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .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(newTagNameButton, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
@ -294,6 +308,9 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//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 private void newTagNameButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagNameButtonActionPerformed
TagNameDialog dialog = new TagNameDialog(); TagNameDialog dialog = new TagNameDialog();
TagNameDialog.BUTTON_PRESSED result = dialog.getResult(); TagNameDialog.BUTTON_PRESSED result = dialog.getResult();
@ -311,8 +328,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
} else { } else {
JOptionPane.showMessageDialog(null, JOptionPane.showMessageDialog(null,
NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.message"), NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.message"),
NbBundle.getMessage(TagOptionsPanel.class, "TagNamesSettingsPanel.JOptionPane.tagNameAlreadyExists.title"), NbBundle.getMessage(TagOptionsPanel.class, "TagOptionsPanel.TagNameDialog.tagNameAlreadyExists.title"),
JOptionPane.INFORMATION_MESSAGE); JOptionPane.INFORMATION_MESSAGE);
} }
} }
@ -337,17 +354,20 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
/* /*
* If tag name already exists, don't add the tag name. * If tag name already exists, don't add the tag name.
*/ */
tagTypes.remove(originalTagName); tagTypes.remove(originalTagName);
tagTypes.add(newTagType); tagTypes.add(newTagType);
updateTagNamesListModel(); updateTagNamesListModel();
tagNamesList.setSelectedValue(newTagType, true); tagNamesList.setSelectedValue(newTagType, true);
updatePanel(); updatePanel();
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
if (originalTagName.getKnownStatus() != newTagType.getKnownStatus() && Case.isCaseOpen()) {
updatedStatusTags.add(newTagType.getDisplayName());
}
} }
}//GEN-LAST:event_editTagNameButtonActionPerformed }//GEN-LAST:event_editTagNameButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JScrollPane TagNameScrollPane;
private javax.swing.JButton deleteTagNameButton; private javax.swing.JButton deleteTagNameButton;
private javax.swing.JLabel descriptionLabel; private javax.swing.JLabel descriptionLabel;
private javax.swing.JScrollPane descriptionScrollPane; private javax.swing.JScrollPane descriptionScrollPane;
@ -356,14 +376,13 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
private javax.swing.JLabel ingestRunningWarningLabel; private javax.swing.JLabel ingestRunningWarningLabel;
private javax.swing.JLabel isNotableLabel; private javax.swing.JLabel isNotableLabel;
private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JScrollPane jScrollPane2; private javax.swing.JScrollPane jScrollPane2;
private javax.swing.JScrollPane jScrollPane3;
private javax.swing.JSplitPane jSplitPane1; private javax.swing.JSplitPane jSplitPane1;
private javax.swing.JTextArea jTextArea1;
private javax.swing.JPanel modifyTagTypesListPanel; private javax.swing.JPanel modifyTagTypesListPanel;
private javax.swing.JButton newTagNameButton; private javax.swing.JButton newTagNameButton;
private javax.swing.JLabel notableYesOrNoLabel; private javax.swing.JLabel notableYesOrNoLabel;
private javax.swing.JScrollPane panelDescriptionScrollPane;
private javax.swing.JTextArea panelDescriptionTextArea;
private javax.swing.JList<org.sleuthkit.autopsy.casemodule.services.TagNameDefinition> tagNamesList; private javax.swing.JList<org.sleuthkit.autopsy.casemodule.services.TagNameDefinition> tagNamesList;
private javax.swing.JPanel tagTypesAdditionalPanel; private javax.swing.JPanel tagTypesAdditionalPanel;
private javax.swing.JLabel tagTypesListLabel; private javax.swing.JLabel tagTypesListLabel;
@ -395,6 +414,21 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
@Override @Override
public void store() { public void store() {
TagNameDefinition.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();
} }
/** /**
@ -414,9 +448,8 @@ final class TagOptionsPanel extends javax.swing.JPanel implements OptionsPanel {
boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName()); boolean enableDelete = enableEdit && !TagNameDefinition.getStandardTagNames().contains(tagNamesList.getSelectedValue().getDisplayName());
deleteTagNameButton.setEnabled(enableDelete); deleteTagNameButton.setEnabled(enableDelete);
if (isSelected) { if (isSelected) {
descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription()); descriptionTextArea.setText(tagNamesList.getSelectedValue().getDescription());
if (tagNamesList.getSelectedValue().isNotable()) { if (tagNamesList.getSelectedValue().getKnownStatus() == TskData.FileKnown.BAD) {
notableYesOrNoLabel.setText("Yes"); notableYesOrNoLabel.setText("Yes");
} else { } else {
notableYesOrNoLabel.setText("No"); notableYesOrNoLabel.setText("No");

View File

@ -27,6 +27,7 @@ import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
@ -69,6 +70,15 @@ public class TagsManager implements Closeable {
|| tagDisplayName.contains(";")); || 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 * Gets the set of display names of the currently available tag types. This
@ -103,7 +113,7 @@ public class TagsManager implements Closeable {
public static List<String> getNotableTagDisplayNames() { public static List<String> getNotableTagDisplayNames() {
List<String> tagDisplayNames = new ArrayList<>(); List<String> tagDisplayNames = new ArrayList<>();
for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) { for (TagNameDefinition tagDef : TagNameDefinition.getTagNameDefinitions()) {
if (tagDef.isNotable()) { if (tagDef.getKnownStatus() == TskData.FileKnown.BAD) {
tagDisplayNames.add(tagDef.getDisplayName()); tagDisplayNames.add(tagDef.getDisplayName());
} }
} }

View File

@ -69,6 +69,7 @@ public final class TagsOptionsPanelController extends OptionsPanelController {
*/ */
@Override @Override
public void cancel() { public void cancel() {
getPanel().cancelChanges();
} }
@Override @Override

View File

@ -2208,8 +2208,13 @@ public abstract class AbstractSqlEamDb implements EamDb {
return eamGlobalFileInstance; return eamGlobalFileInstance;
} }
void updateSchema() { /**
* Update the schema of the database (if needed)
* @throws EamDbException
*/
@Override
public void updateSchema() throws EamDbException {
ResultSet resultSet = null; ResultSet resultSet = null;
Statement statement; Statement statement;
@ -2244,10 +2249,13 @@ public abstract class AbstractSqlEamDb implements EamDb {
System.out.println("Current schema version: " + majorVersion + "." + minorVersion); System.out.println("Current schema version: " + majorVersion + "." + minorVersion);
CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion); CaseDbSchemaVersionNumber dbSchemaVersion = new CaseDbSchemaVersionNumber(majorVersion, minorVersion);
// Update from 1.0 to 1.1
if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) { if (dbSchemaVersion.compareTo(new CaseDbSchemaVersionNumber(1, 1)) < 0) {
statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS statement.execute("ALTER TABLE reference_sets ADD COLUMN known_status INTEGER;"); //NON-NLS
statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS statement.execute("ALTER TABLE reference_sets ADD COLUMN read_only BOOLEAN;"); //NON-NLS
statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS statement.execute("ALTER TABLE reference_sets ADD COLUMN type INTEGER;"); //NON-NLS
statement.execute("INSERT INTO organizations (name) VALUES (" + EamDbUtil.getDefaultOrgName() + ")");
} }
if (!updateSchemaVersion(conn)) { if (!updateSchemaVersion(conn)) {
@ -2268,11 +2276,6 @@ public abstract class AbstractSqlEamDb implements EamDb {
ex.printStackTrace(); ex.printStackTrace();
} finally { } finally {
EamDbUtil.closeResultSet(resultSet); EamDbUtil.closeResultSet(resultSet);
try {
conn.setAutoCommit(true);
} catch (SQLException ex) {
ex.printStackTrace();
}
} }
} }

View File

@ -38,6 +38,7 @@ public class EamDbUtil {
private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName()); private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName());
private static final String CENTRAL_REPO_NAME = "CentralRepository"; private static final String CENTRAL_REPO_NAME = "CentralRepository";
private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo"; private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo";
private static final String DEFAULT_ORG_NAME = "Not Specified";
/** /**
* Close the prepared statement. * Close the prepared statement.
@ -233,6 +234,54 @@ public class EamDbUtil {
} }
} }
} }
/**
* Get the default organization name
* @return the default org name
*/
static String getDefaultOrgName() {
return DEFAULT_ORG_NAME;
}
/**
* 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. * If the Central Repos use has been enabled.

View File

@ -485,7 +485,8 @@ public final class PostgresEamDbSettings {
} }
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
&& EamDbUtil.updateSchemaVersion(conn); && EamDbUtil.updateSchemaVersion(conn)
&& EamDbUtil.insertDefaultOrganization(conn);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
return result; return result;

View File

@ -85,11 +85,6 @@ public final class SqliteEamDbSettings {
} catch (NumberFormatException ex) { } catch (NumberFormatException ex) {
this.bulkThreshold = DEFAULT_BULK_THRESHHOLD; this.bulkThreshold = DEFAULT_BULK_THRESHHOLD;
} }
System.out.println("\n#### UPDATING DATABASE!!!");
EamDbUtil.updateSchema(getEphemeralConnection());
} }
public void saveSettings() { public void saveSettings() {
@ -437,7 +432,8 @@ public final class SqliteEamDbSettings {
} }
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn) boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
&& EamDbUtil.updateSchemaVersion(conn); && EamDbUtil.updateSchemaVersion(conn)
&& EamDbUtil.insertDefaultOrganization(conn);
EamDbUtil.closeConnection(conn); EamDbUtil.closeConnection(conn);
return result; return result;
} }

View File

@ -48,6 +48,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifactTag; import org.sleuthkit.datamodel.BlackboardArtifactTag;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskDataException; import org.sleuthkit.datamodel.TskDataException;
@ -97,7 +98,10 @@ final class CaseEventListener implements PropertyChangeListener {
jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt)); jobProcessingExecutor.submit(new DataSourceAddedTask(dbManager, evt));
} }
break; break;
case TAG_DEFINITION_CHANGED: {
jobProcessingExecutor.submit(new TagDefinitionChangeTask(evt));
}
break;
case CURRENT_CASE: { case CURRENT_CASE: {
jobProcessingExecutor.submit(new CurrentCaseTask(dbManager, evt)); 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<BlackboardArtifactTag> 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<BlackboardArtifactTag> 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<CorrelationAttribute> convertedArtifacts = EamArtifactUtil.getCorrelationAttributeFromBlackboardArtifact(bbTag.getArtifact(), true, true);
for (CorrelationAttribute eamArtifact : convertedArtifacts) {
EamDb.getInstance().setArtifactInstanceKnownStatus(eamArtifact, tagName.getKnownStatus());
}
}
}
// Next update the files
List<ContentTag> 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<ContentTag> 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 class DataSourceAddedTask implements Runnable {
private final EamDb dbManager; private final EamDb dbManager;
@ -350,7 +465,7 @@ final class CaseEventListener implements PropertyChangeListener {
if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) { if ((null == event.getOldValue()) && (event.getNewValue() instanceof Case)) {
Case curCase = (Case) event.getNewValue(); Case curCase = (Case) event.getNewValue();
IngestEventsListener.resetCeModuleInstanceCount(); IngestEventsListener.resetCeModuleInstanceCount();
CorrelationCase curCeCase = new CorrelationCase( CorrelationCase curCeCase = new CorrelationCase(
-1, -1,
curCase.getName(), // unique case ID curCase.getName(), // unique case ID

View File

@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; 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.EamOrganization;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -72,7 +73,7 @@ public final class ManageOrganizationsDialog extends JDialog {
organizationList.setModel(rulesListModel); organizationList.setModel(rulesListModel);
organizationList.addListSelectionListener(new OrganizationListSelectionListener()); organizationList.addListSelectionListener(new OrganizationListSelectionListener());
populateList(); populateList();
setButtonsEnabled(organizationList.getSelectedValue() != null); setButtonsEnabled(organizationList.getSelectedValue());
newOrg = null; newOrg = null;
} catch (EamDbException ex) { } catch (EamDbException ex) {
Exceptions.printStackTrace(ex); Exceptions.printStackTrace(ex);
@ -421,9 +422,15 @@ public final class ManageOrganizationsDialog extends JDialog {
return newOrg; return newOrg;
} }
private void setButtonsEnabled(boolean isSelected) { private void setButtonsEnabled(EamOrganization selectedOrg) {
editButton.setEnabled(isSelected); boolean isSelected = (selectedOrg != null);
deleteButton.setEnabled(isSelected); 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()) { if (e.getValueIsAdjusting()) {
return; return;
} }
EamOrganization selected = organizationList.getSelectedValue(); EamOrganization selected = organizationList.getSelectedValue();
boolean isSelected = (selected != null); setButtonsEnabled(selected);
setButtonsEnabled(isSelected);
if (selected != null) { if (selected != null) {
orgNameTextField.setText(selected.getName()); orgNameTextField.setText(selected.getName());
pocNameTextField.setText(selected.getPocName()); pocNameTextField.setText(selected.getPocName());

View File

@ -22,12 +22,18 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="1" max="32767" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane1" pref="672" max="32767" attributes="0"/>
<EmptySpace min="-2" pref="0" max="-2" attributes="0"/>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jScrollPane1" alignment="0" max="32767" attributes="0"/> <Group type="102" alignment="0" attributes="0">
<Component id="jScrollPane1" min="-2" pref="489" max="-2" attributes="0"/>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
@ -46,247 +52,336 @@
<Layout> <Layout>
<DimensionLayout dim="0"> <DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Group type="102" attributes="0"> <Component id="viewPanel" max="32767" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Component id="logoPanel" max="32767" attributes="0"/>
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace pref="140" max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="agencyLogoImageLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="agencyLogoPathField" min="-2" pref="259" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseLogosButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
</Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/> <Component id="viewPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/> <Component id="logoPanel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="0" pref="0" max="-2" attributes="0"/>
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="jLabelHideKnownFiles" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideKnownCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelHideSlackFiles" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="dataSourcesHideSlackCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="viewsHideSlackCB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelTimeDisplay" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="useGMTTimeRB" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="agencyLogoImageLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="agencyLogoPathField" alignment="3" max="32767" attributes="0"/>
<Component id="browseLogosButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
</Layout> </Layout>
<SubComponents> <SubComponents>
<Component class="javax.swing.JRadioButton" name="useBestViewerRB"> <Container class="javax.swing.JPanel" name="logoPanel">
<Properties> <Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<ComponentRef name="buttonGroup1"/> <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
</Property> <TitledBorder title="Logo">
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.logoPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useBestViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> </TitledBorder>
</Property> </Border>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useBestViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useBestViewerRBActionPerformed"/> <Layout>
</Events> <DimensionLayout dim="0">
</Component> <Group type="103" groupAlignment="0" attributes="0">
<Component class="javax.swing.JRadioButton" name="keepCurrentViewerRB"> <Group type="102" alignment="1" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="agencyLogoImageLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
<Component id="agencyLogoPathField" min="-2" pref="259" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="browseLogosButton" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="agencyLogoPreview" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="149" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="agencyLogoPreview" alignment="1" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="agencyLogoImageLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="agencyLogoPathField" alignment="3" max="32767" attributes="0"/>
<Component id="browseLogosButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group>
<EmptySpace min="0" pref="0" max="-2" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JLabel" name="agencyLogoImageLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoImageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="agencyLogoPathField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="ff" green="ff" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoPathField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseLogosButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.browseLogosButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseLogosButtonActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="agencyLogoPreview">
<Properties>
<Property name="horizontalAlignment" type="int" value="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoPreview.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.EtchedBorderInfo">
<EtchetBorder/>
</Border>
</Property>
<Property name="maximumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[64, 64]"/>
</Property>
<Property name="minimumSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[64, 64]"/>
</Property>
<Property name="preferredSize" type="java.awt.Dimension" editor="org.netbeans.beaninfo.editors.DimensionEditor">
<Dimension value="[64, 64]"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Container>
<Container class="javax.swing.JPanel" name="viewPanel">
<Properties> <Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<ComponentRef name="buttonGroup1"/> <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
</Property> <TitledBorder title="View">
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.keepCurrentViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> </TitledBorder>
</Property> </Border>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="keepCurrentViewerRBActionPerformed"/> <Layout>
</Events> <DimensionLayout dim="0">
</Component> <Group type="103" groupAlignment="0" attributes="0">
<Component class="javax.swing.JLabel" name="jLabelSelectFile"> <Group type="102" alignment="1" attributes="0">
<Properties> <EmptySpace max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Group type="103" groupAlignment="0" attributes="0">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelSelectFile.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Group type="102" alignment="0" attributes="0">
</Property> <EmptySpace min="-2" pref="10" max="-2" attributes="0"/>
</Properties> <Group type="103" groupAlignment="0" attributes="0">
</Component> <Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component class="javax.swing.JLabel" name="jLabelTimeDisplay"> <Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<Properties> <Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Group type="103" alignment="0" groupAlignment="0" attributes="0">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelTimeDisplay.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Component id="useLocalTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
</Property> <Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
</Properties> <Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
</Component> <Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Component class="javax.swing.JRadioButton" name="useLocalTimeRB"> <Component id="viewsHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
<Properties> </Group>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> </Group>
<ComponentRef name="buttonGroup3"/> </Group>
</Property> <Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useLocalTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
</Property> <Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
</Properties> </Group>
<Events> <EmptySpace max="32767" attributes="0"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRBActionPerformed"/> </Group>
</Events> </Group>
</Component> </DimensionLayout>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRB"> <DimensionLayout dim="1">
<Properties> <Group type="103" groupAlignment="0" attributes="0">
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor"> <Group type="102" alignment="1" attributes="0">
<ComponentRef name="buttonGroup3"/> <EmptySpace max="-2" attributes="0"/>
</Property> <Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <EmptySpace max="-2" attributes="0"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useGMTTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
</Property> <EmptySpace max="-2" attributes="0"/>
</Properties> <Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
<Events> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRBActionPerformed"/> <Component id="jLabelHideKnownFiles" min="-2" max="-2" attributes="0"/>
</Events> <EmptySpace max="-2" attributes="0"/>
</Component> <Component id="dataSourcesHideKnownCB" min="-2" max="-2" attributes="0"/>
<Component class="javax.swing.JLabel" name="jLabelHideKnownFiles"> <EmptySpace max="-2" attributes="0"/>
<Properties> <Component id="viewsHideKnownCB" min="-2" max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <EmptySpace max="-2" attributes="0"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideKnownFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Component id="jLabelHideSlackFiles" min="-2" max="-2" attributes="0"/>
</Property> <EmptySpace max="-2" attributes="0"/>
</Properties> <Component id="dataSourcesHideSlackCB" min="-2" max="-2" attributes="0"/>
</Component> <EmptySpace max="-2" attributes="0"/>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideKnownCB"> <Component id="viewsHideSlackCB" min="-2" max="-2" attributes="0"/>
<Properties> <EmptySpace max="-2" attributes="0"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Component id="jLabelTimeDisplay" min="-2" max="-2" attributes="0"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <EmptySpace max="-2" attributes="0"/>
</Property> <Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
</Properties> <EmptySpace min="-2" max="-2" attributes="0"/>
<Events> <Component id="useGMTTimeRB" min="-2" max="-2" attributes="0"/>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideKnownCBActionPerformed"/> </Group>
</Events> </Group>
</Component> </DimensionLayout>
<Component class="javax.swing.JCheckBox" name="viewsHideKnownCB"> </Layout>
<Properties> <SubComponents>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Component class="javax.swing.JLabel" name="jLabelSelectFile">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Properties>
</Property> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Properties> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelSelectFile.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Events> </Property>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideKnownCBActionPerformed"/> </Properties>
</Events> </Component>
</Component> <Component class="javax.swing.JRadioButton" name="useBestViewerRB">
<Component class="javax.swing.JCheckBox" name="dataSourcesHideSlackCB"> <Properties>
<Properties> <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <ComponentRef name="buttonGroup1"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> </Property>
</Property> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Properties> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useBestViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Events> </Property>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideSlackCBActionPerformed"/> <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Events> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useBestViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Component> </Property>
<Component class="javax.swing.JCheckBox" name="viewsHideSlackCB"> </Properties>
<Properties> <Events>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useBestViewerRBActionPerformed"/>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> </Events>
</Property> </Component>
</Properties> <Component class="javax.swing.JRadioButton" name="keepCurrentViewerRB">
<Events> <Properties>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideSlackCBActionPerformed"/> <Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
</Events> <ComponentRef name="buttonGroup1"/>
</Component> </Property>
<Component class="javax.swing.JLabel" name="jLabelHideSlackFiles"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<Properties> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.keepCurrentViewerRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> </Property>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideSlackFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Property> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.keepCurrentViewerRB.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Properties> </Property>
</Component> </Properties>
<Component class="javax.swing.JLabel" name="agencyLogoImageLabel"> <Events>
<Properties> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="keepCurrentViewerRBActionPerformed"/>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> </Events>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoImageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> </Component>
</Property> <Component class="javax.swing.JLabel" name="jLabelHideKnownFiles">
</Properties> <Properties>
</Component> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<Component class="javax.swing.JTextField" name="agencyLogoPathField"> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideKnownFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
<Properties> </Property>
<Property name="editable" type="boolean" value="false"/> </Properties>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor"> </Component>
<Color blue="ff" green="ff" red="ff" type="rgb"/> <Component class="javax.swing.JCheckBox" name="dataSourcesHideKnownCB">
</Property> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoPathField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="focusable" type="boolean" value="false"/> </Properties>
<Property name="requestFocusEnabled" type="boolean" value="false"/> <Events>
</Properties> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideKnownCBActionPerformed"/>
</Component> </Events>
<Component class="javax.swing.JButton" name="browseLogosButton"> </Component>
<Properties> <Component class="javax.swing.JCheckBox" name="viewsHideKnownCB">
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Properties>
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.browseLogosButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
</Property> <ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideKnownCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Properties> </Property>
<Events> </Properties>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseLogosButtonActionPerformed"/> <Events>
</Events> <EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideKnownCBActionPerformed"/>
</Component> </Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelHideSlackFiles">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelHideSlackFiles.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="dataSourcesHideSlackCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.dataSourcesHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="dataSourcesHideSlackCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="viewsHideSlackCB">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.viewsHideSlackCB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="viewsHideSlackCBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JLabel" name="jLabelTimeDisplay">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.jLabelTimeDisplay.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JRadioButton" name="useLocalTimeRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup3"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useLocalTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useLocalTimeRBActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JRadioButton" name="useGMTTimeRB">
<Properties>
<Property name="buttonGroup" type="javax.swing.ButtonGroup" editor="org.netbeans.modules.form.RADComponent$ButtonGroupPropertyEditor">
<ComponentRef name="buttonGroup3"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.useGMTTimeRB.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="useGMTTimeRBActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents> </SubComponents>
</Container> </Container>
</SubComponents> </SubComponents>

View File

@ -18,9 +18,18 @@
*/ */
package org.sleuthkit.autopsy.corecomponents; package org.sleuthkit.autopsy.corecomponents;
import java.awt.image.BufferedImage;
import java.io.File; import java.io.File;
import java.io.IOException;
import java.util.logging.Level;
import javax.imageio.ImageIO;
import javax.swing.ImageIcon;
import javax.swing.JFileChooser; import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import org.netbeans.spi.options.OptionsPanelController; 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.casemodule.GeneralFilter;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
import org.sleuthkit.autopsy.coreutils.ModuleSettings; import org.sleuthkit.autopsy.coreutils.ModuleSettings;
@ -29,16 +38,23 @@ import org.sleuthkit.autopsy.report.ReportBranding;
/** /**
* Options panel that allow users to set application preferences. * Options panel that allow users to set application preferences.
*/ */
@Messages({"AutopsyOptionsPanel.agencyLogoPreview.text=<html><div style='text-align: center;'>No logo<br>selected</div></html>",
"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"})
final class AutopsyOptionsPanel extends javax.swing.JPanel { final class AutopsyOptionsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private final JFileChooser fc; private final JFileChooser fc;
private static final Logger logger = Logger.getLogger(AutopsyOptionsPanel.class.getName());
AutopsyOptionsPanel() { AutopsyOptionsPanel() {
initComponents(); initComponents();
fc = new JFileChooser(); fc = new JFileChooser();
fc.setFileSelectionMode(JFileChooser.FILES_ONLY); fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
fc.setMultiSelectionEnabled(false); fc.setMultiSelectionEnabled(false);
fc.setAcceptAllFileFilterUsed(false);
fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR)); fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
} }
@ -53,7 +69,31 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
boolean useLocalTime = UserPreferences.displayTimesInLocalTime(); boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRB.setSelected(useLocalTime); useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.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);
}
}
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() { void store() {
@ -64,8 +104,8 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected()); UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected()); UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
if (!agencyLogoPathField.getText().isEmpty()) { if (!agencyLogoPathField.getText().isEmpty()) {
File image = new File(agencyLogoPathField.getText()); File file = new File(agencyLogoPathField.getText());
if (image.exists()) { if (file.exists()) {
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText()); ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
} }
} }
@ -87,24 +127,87 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
buttonGroup3 = new javax.swing.ButtonGroup(); buttonGroup3 = new javax.swing.ButtonGroup();
jScrollPane1 = new javax.swing.JScrollPane(); jScrollPane1 = new javax.swing.JScrollPane();
jPanel1 = new javax.swing.JPanel(); jPanel1 = new javax.swing.JPanel();
useBestViewerRB = new javax.swing.JRadioButton(); logoPanel = new javax.swing.JPanel();
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();
agencyLogoImageLabel = new javax.swing.JLabel(); agencyLogoImageLabel = new javax.swing.JLabel();
agencyLogoPathField = new javax.swing.JTextField(); agencyLogoPathField = new javax.swing.JTextField();
browseLogosButton = new javax.swing.JButton(); 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();
jScrollPane1.setBorder(null); 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(149, 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); buttonGroup1.add(useBestViewerRB);
org.openide.awt.Mnemonics.setLocalizedText(useBestViewerRB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.text")); // NOI18N 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 useBestViewerRB.setToolTipText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.useBestViewerRB.toolTipText")); // NOI18N
@ -123,7 +226,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 org.openide.awt.Mnemonics.setLocalizedText(jLabelTimeDisplay, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelTimeDisplay.text")); // NOI18N
@ -143,93 +276,34 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideKnownFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideKnownFiles.text")); // NOI18N javax.swing.GroupLayout viewPanelLayout = new javax.swing.GroupLayout(viewPanel);
viewPanel.setLayout(viewPanelLayout);
org.openide.awt.Mnemonics.setLocalizedText(dataSourcesHideKnownCB, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.dataSourcesHideKnownCB.text")); // NOI18N viewPanelLayout.setHorizontalGroup(
dataSourcesHideKnownCB.addActionListener(new java.awt.event.ActionListener() { viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
public void actionPerformed(java.awt.event.ActionEvent evt) { .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
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()
.addContainerGap() .addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(viewPanelLayout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGap(10, 10, 10)
.addComponent(jLabelTimeDisplay) .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelHideKnownFiles) .addComponent(useGMTTimeRB)
.addComponent(jLabelSelectFile) .addComponent(keepCurrentViewerRB)
.addGroup(jPanel1Layout.createSequentialGroup() .addComponent(useBestViewerRB)
.addGap(10, 10, 10) .addGroup(viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(useLocalTimeRB)
.addComponent(useLocalTimeRB) .addComponent(dataSourcesHideSlackCB)
.addComponent(useGMTTimeRB) .addComponent(viewsHideSlackCB)
.addComponent(keepCurrentViewerRB) .addComponent(dataSourcesHideKnownCB)
.addComponent(useBestViewerRB) .addComponent(viewsHideKnownCB))))
.addComponent(dataSourcesHideKnownCB) .addComponent(jLabelHideSlackFiles)
.addComponent(viewsHideKnownCB)))) .addComponent(jLabelTimeDisplay)
.addContainerGap(140, Short.MAX_VALUE)) .addComponent(jLabelHideKnownFiles)
.addGroup(jPanel1Layout.createSequentialGroup() .addComponent(jLabelSelectFile))
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.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(dataSourcesHideSlackCB)
.addComponent(viewsHideSlackCB))))
.addGap(0, 0, Short.MAX_VALUE))))
); );
jPanel1Layout.setVerticalGroup( viewPanelLayout.setVerticalGroup(
jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) viewPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, viewPanelLayout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addComponent(jLabelSelectFile) .addComponent(jLabelSelectFile)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
@ -253,14 +327,28 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useLocalTimeRB) .addComponent(useLocalTimeRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(useGMTTimeRB) .addComponent(useGMTTimeRB))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) );
.addComponent(agencyLogoImageLabel)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) jPanel1.setLayout(jPanel1Layout);
.addComponent(agencyLogoPathField) jPanel1Layout.setHorizontalGroup(
.addComponent(browseLogosButton)) jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGap(35, 35, 35)) .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
.addContainerGap()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(viewPanel, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(logoPanel, 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)
.addGap(0, 0, 0)
.addComponent(logoPanel, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, 0))
); );
jScrollPane1.setViewportView(jPanel1); jScrollPane1.setViewportView(jPanel1);
@ -269,11 +357,15 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
this.setLayout(layout); this.setLayout(layout);
layout.setHorizontalGroup( layout.setHorizontalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1, javax.swing.GroupLayout.Alignment.TRAILING) .addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.DEFAULT_SIZE, 672, Short.MAX_VALUE)
.addGap(0, 0, 0))
); );
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jScrollPane1) .addGroup(layout.createSequentialGroup()
.addComponent(jScrollPane1, javax.swing.GroupLayout.PREFERRED_SIZE, 489, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(0, 0, Short.MAX_VALUE))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
@ -310,17 +402,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
}//GEN-LAST:event_viewsHideSlackCBActionPerformed }//GEN-LAST:event_viewsHideSlackCBActionPerformed
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
String oldLogoPath = agencyLogoPathField.getText();
int returnState = fc.showOpenDialog(this); int returnState = fc.showOpenDialog(this);
if (returnState == JFileChooser.APPROVE_OPTION) { if (returnState == JFileChooser.APPROVE_OPTION) {
String path = fc.getSelectedFile().getPath(); String path = fc.getSelectedFile().getPath();
agencyLogoPathField.setText(path); try {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null); 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 }//GEN-LAST:event_browseLogosButtonActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JLabel agencyLogoImageLabel; private javax.swing.JLabel agencyLogoImageLabel;
private javax.swing.JTextField agencyLogoPathField; private javax.swing.JTextField agencyLogoPathField;
private javax.swing.JLabel agencyLogoPreview;
private javax.swing.JButton browseLogosButton; private javax.swing.JButton browseLogosButton;
private javax.swing.ButtonGroup buttonGroup1; private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.ButtonGroup buttonGroup3; private javax.swing.ButtonGroup buttonGroup3;
@ -333,9 +440,11 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
private javax.swing.JPanel jPanel1; private javax.swing.JPanel jPanel1;
private javax.swing.JScrollPane jScrollPane1; private javax.swing.JScrollPane jScrollPane1;
private javax.swing.JRadioButton keepCurrentViewerRB; private javax.swing.JRadioButton keepCurrentViewerRB;
private javax.swing.JPanel logoPanel;
private javax.swing.JRadioButton useBestViewerRB; private javax.swing.JRadioButton useBestViewerRB;
private javax.swing.JRadioButton useGMTTimeRB; private javax.swing.JRadioButton useGMTTimeRB;
private javax.swing.JRadioButton useLocalTimeRB; private javax.swing.JRadioButton useLocalTimeRB;
private javax.swing.JPanel viewPanel;
private javax.swing.JCheckBox viewsHideKnownCB; private javax.swing.JCheckBox viewsHideKnownCB;
private javax.swing.JCheckBox viewsHideSlackCB; private javax.swing.JCheckBox viewsHideSlackCB;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables

View File

@ -1,7 +1,7 @@
CTL_DataContentAction=DataContent CTL_DataContentAction=DataContent
CTL_DataContentTopComponent=Data Content CTL_DataContentTopComponent=Data Content
CTL_CustomAboutAction=About CTL_CustomAboutAction=About
OptionsCategory_Name_General=View OptionsCategory_Name_General=Application
OptionsCategory_Keywords_General=Autopsy Options OptionsCategory_Keywords_General=Autopsy Options
HINT_DataContentTopComponent=This is a DataContent window HINT_DataContentTopComponent=This is a DataContent window
HINT_NodeTableTopComponent=This is a DataResult window HINT_NodeTableTopComponent=This is a DataResult window
@ -198,7 +198,6 @@ AutopsyOptionsPanel.agencyLogoPathField.text=
SortChooserDialog.label=remove SortChooserDialog.label=remove
SortChooser.addCriteriaButton.text=Add Sort Criteria SortChooser.addCriteriaButton.text=Add Sort Criteria
DataResultViewerThumbnail.sortButton.text=Sort DataResultViewerThumbnail.sortButton.text=Sort
CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n CriterionChooser.ascendingRadio.text=\u25b2 Ascending\n
CriterionChooser.removeButton.text=Remove CriterionChooser.removeButton.text=Remove
CriterionChooser.descendingRadio.text=\u25bc Descending CriterionChooser.descendingRadio.text=\u25bc Descending

View File

@ -38,6 +38,7 @@ public class FileTypeExtensions {
private final static List<String> WEB_EXTENSIONS = Arrays.asList(".html", ".htm", ".css", ".js", ".php", ".aspx"); //NON-NLS private final static List<String> WEB_EXTENSIONS = Arrays.asList(".html", ".htm", ".css", ".js", ".php", ".aspx"); //NON-NLS
private final static List<String> PDF_EXTENSIONS = Arrays.asList(".pdf"); //NON-NLS private final static List<String> PDF_EXTENSIONS = Arrays.asList(".pdf"); //NON-NLS
private final static List<String> 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<String> 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<String> DATABASE_EXTENSIONS = Arrays.asList(".db", ".db3", ".sqlite", ".sqlite3"); //NON-NLS
public static List<String> getImageExtensions() { public static List<String> getImageExtensions() {
return IMAGE_EXTENSIONS; return IMAGE_EXTENSIONS;
@ -75,6 +76,10 @@ public class FileTypeExtensions {
return ARCHIVE_EXTENSIONS; return ARCHIVE_EXTENSIONS;
} }
public static List<String> getDatabaseExtensions() {
return DATABASE_EXTENSIONS;
}
private FileTypeExtensions() { private FileTypeExtensions() {
} }

View File

@ -34,6 +34,7 @@ import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.core.UserPreferences; import org.sleuthkit.autopsy.core.UserPreferences;
@ -423,6 +424,7 @@ public final class FileTypesByExtension implements AutopsyVisitableItem {
} }
// root node filters // root node filters
@Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface { public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS 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 TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"), NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
FileTypeExtensions.getArchiveExtensions()), 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"), NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS 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"), NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
FileTypeExtensions.getExecutableExtensions()); //NON-NLS FileTypeExtensions.getExecutableExtensions()); //NON-NLS

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2017 Basis Technology Corp. * Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * 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 static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS
private String moduleDirRelative; private String moduleDirRelative;
private String moduleDirAbsolute; private String moduleDirAbsolute;
private ImageExtractor imageExtractor; private MSOfficeEmbeddedContentExtractor officeExtractor;
private SevenZipExtractor archiveExtractor; private SevenZipExtractor archiveExtractor;
private FileTypeDetector fileTypeDetector; 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. * Office documents.
*/ */
this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute); this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute);
} }
@Override @Override
@ -134,8 +134,8 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
*/ */
if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) { if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) {
archiveExtractor.unpack(abstractFile); archiveExtractor.unpack(abstractFile);
} else if (imageExtractor.isImageExtractionSupported(abstractFile)) { } else if (officeExtractor.isContentExtractionSupported(abstractFile)) {
imageExtractor.extractImage(abstractFile); officeExtractor.extractEmbeddedContent(abstractFile);
} }
return ProcessResult.OK; return ProcessResult.OK;
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2017 Basis Technology Corp. * Copyright 2015 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * 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.File;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.lang.IllegalArgumentException; import java.io.InputStream;
import java.lang.IndexOutOfBoundsException;
import java.lang.NullPointerException;
import java.nio.file.Paths; import java.nio.file.Paths;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.logging.Level; 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.hwpf.usermodel.Picture;
import org.apache.poi.hslf.usermodel.HSLFPictureData; import org.apache.poi.hslf.usermodel.HSLFPictureData;
import org.apache.poi.hslf.usermodel.HSLFSlideShow; 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.sl.usermodel.PictureData.PictureType;
import org.apache.poi.ss.usermodel.Workbook; import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.util.RecordFormatException; import org.apache.poi.util.RecordFormatException;
import org.apache.poi.xslf.usermodel.XMLSlideShow; import org.apache.tika.config.TikaConfig;
import org.apache.poi.xslf.usermodel.XSLFPictureData; import org.apache.tika.detect.Detector;
import org.apache.poi.xssf.usermodel.XSSFWorkbook; import org.apache.tika.exception.TikaException;
import org.apache.poi.xwpf.usermodel.XWPFDocument; import org.apache.tika.extractor.EmbeddedDocumentExtractor;
import org.apache.poi.xwpf.usermodel.XWPFPictureData; 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.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.FileManager; 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.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; 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 FileManager fileManager;
private final IngestServices services; 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 final IngestJobContext context;
private String parentFileName; 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 final FileTypeDetector fileTypeDetector;
private String moduleDirRelative; private String moduleDirRelative;
private String moduleDirAbsolute; 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 DOC("application/msword"), //NON-NLS
DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS
@ -85,7 +104,7 @@ class ImageExtractor {
private final String mimeType; private final String mimeType;
SupportedImageExtractionFormats(final String mimeType) { SupportedExtractionFormats(final String mimeType) {
this.mimeType = mimeType; this.mimeType = mimeType;
} }
@ -93,11 +112,10 @@ class ImageExtractor {
public String toString() { public String toString() {
return this.mimeType; 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.fileManager = Case.getCurrentCase().getServices().getFileManager();
this.services = IngestServices.getInstance(); this.services = IngestServices.getInstance();
@ -111,15 +129,15 @@ class ImageExtractor {
* This method returns true if the file format is currently supported. Else * This method returns true if the file format is currently supported. Else
* it returns false. Performs only Apache Tika based detection. * 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 * @return This method returns true if the file format is currently
* supported. Else it returns false. * supported. Else it returns false.
*/ */
boolean isImageExtractionSupported(AbstractFile abstractFile) { boolean isContentExtractionSupported(AbstractFile abstractFile) {
try { try {
String abstractFileMimeType = fileTypeDetector.getFileType(abstractFile); String abstractFileMimeType = fileTypeDetector.getFileType(abstractFile);
for (SupportedImageExtractionFormats s : SupportedImageExtractionFormats.values()) { for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) {
if (s.toString().equals(abstractFileMimeType)) { if (s.toString().equals(abstractFileMimeType)) {
abstractFileExtractionFormat = s; abstractFileExtractionFormat = s;
return true; return true;
@ -127,60 +145,55 @@ class ImageExtractor {
} }
return false; return false;
} catch (TskCoreException ex) { } 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; return false;
} }
} }
/** /**
* This method selects the appropriate process of extracting images from * This method selects the appropriate process of extracting embedded
* files using POI classes. Once the images have been extracted, the method * content from files using either Tika or POI classes. Once the content has
* adds them to the DB and fires a ModuleContentEvent. ModuleContent Event * been extracted as files, the method adds them to the DB and fires a
* is not fired if the no images were extracted from the processed file. * 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. * @param abstractFile The abstract file to be processed.
*/ */
void extractImage(AbstractFile abstractFile) { void extractEmbeddedContent(AbstractFile abstractFile) {
// List<ExtractedFile> listOfExtractedImages = null;
// switchcase for different supported formats
// process abstractFile according to the format by calling appropriate methods.
List<ExtractedImage> listOfExtractedImages = null;
List<AbstractFile> listOfExtractedImageAbstractFiles = null; List<AbstractFile> listOfExtractedImageAbstractFiles = null;
this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile); this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile);
//check if already has derived files, skip
// Skip files that already have been unpacked.
try { try {
if (abstractFile.hasChildren()) { if (abstractFile.hasChildren()) {
//check if local unpacked dir exists //check if local unpacked dir exists
if (new File(getOutputFolderPath(parentFileName)).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; return;
} }
} }
} catch (TskCoreException e) { } 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; return;
} }
// Call the appropriate extraction method based on mime type
switch (abstractFileExtractionFormat) { switch (abstractFileExtractionFormat) {
case DOC:
listOfExtractedImages = extractImagesFromDoc(abstractFile);
break;
case DOCX: case DOCX:
listOfExtractedImages = extractImagesFromDocx(abstractFile); case PPTX:
case XLSX:
listOfExtractedImages = extractEmbeddedContentFromOOXML(abstractFile);
break;
case DOC:
listOfExtractedImages = extractEmbeddedImagesFromDoc(abstractFile);
break; break;
case PPT: case PPT:
listOfExtractedImages = extractImagesFromPpt(abstractFile); listOfExtractedImages = extractEmbeddedImagesFromPpt(abstractFile);
break;
case PPTX:
listOfExtractedImages = extractImagesFromPptx(abstractFile);
break; break;
case XLS: case XLS:
listOfExtractedImages = extractImagesFromXls(abstractFile); listOfExtractedImages = extractImagesFromXls(abstractFile);
break; break;
case XLSX:
listOfExtractedImages = extractImagesFromXlsx(abstractFile);
break;
default: default:
break; break;
} }
@ -190,13 +203,13 @@ class ImageExtractor {
} }
// the common task of adding abstractFile to derivedfiles is performed. // the common task of adding abstractFile to derivedfiles is performed.
listOfExtractedImageAbstractFiles = new ArrayList<>(); listOfExtractedImageAbstractFiles = new ArrayList<>();
for (ExtractedImage extractedImage : listOfExtractedImages) { for (ExtractedFile extractedImage : listOfExtractedImages) {
try { try {
listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(), listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(),
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(), extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1)); true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
} catch (TskCoreException ex) { } 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()) { 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<ExtractedFile> 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. * @param af the file from which images are to be extracted.
* *
* @return list of extracted images. Returns null in case no images were * @return list of extracted images. Returns null in case no images were
* extracted. * extracted.
*/ */
private List<ExtractedImage> extractImagesFromDoc(AbstractFile af) { private List<ExtractedFile> extractEmbeddedImagesFromDoc(AbstractFile af) {
List<Picture> listOfAllPictures; List<Picture> listOfAllPictures;
try { try {
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af)); HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
PicturesTable pictureTable = doc.getPicturesTable(); PicturesTable pictureTable = doc.getPicturesTable();
listOfAllPictures = pictureTable.getAllPictures(); listOfAllPictures = pictureTable.getAllPictures();
} catch (IOException | IllegalArgumentException | } catch (IOException | IllegalArgumentException
IndexOutOfBoundsException | NullPointerException ex) { | IndexOutOfBoundsException | NullPointerException ex) {
// IOException: // IOException:
// Thrown when the document has issues being read. // Thrown when the document has issues being read.
// IllegalArgumentException: // IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the // This will catch OldFileFormatException, which is thrown when the
// document's format is Word 95 or older. Alternatively, this is // document's format is Word 95 or older. Alternatively, this is
// thrown when attempting to load an RTF file as a DOC file. // thrown when attempting to load an RTF file as a DOC file.
// However, our code verifies the file format before ever running it // 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. // "IN10-0137.E01" image regardless. The reason is unknown.
// IndexOutOfBoundsException: // IndexOutOfBoundsException:
// NullPointerException: // NullPointerException:
// These get thrown in certain images. The reason is unknown. It is // These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly // likely due to problems with the file formats that POI is poorly
// handling. // handling.
return null; return null;
} catch (Throwable ex) { } catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions // 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; return null;
} }
@ -255,7 +304,7 @@ class ImageExtractor {
if (outputFolderPath == null) { if (outputFolderPath == null) {
return null; return null;
} }
List<ExtractedImage> listOfExtractedImages = new ArrayList<>(); List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
byte[] data = null; byte[] data = null;
for (Picture picture : listOfAllPictures) { for (Picture picture : listOfAllPictures) {
String fileName = picture.suggestFullFileName(); String fileName = picture.suggestFullFileName();
@ -266,99 +315,43 @@ class ImageExtractor {
} }
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data); writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
// TODO Extract more info from the Picture viz ctime, crtime, atime, mtime // 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; 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. * @param af the file from which images are to be extracted.
* *
* @return list of extracted images. Returns null in case no images were * @return list of extracted images. Returns null in case no images were
* extracted. * extracted.
*/ */
private List<ExtractedImage> extractImagesFromDocx(AbstractFile af) { private List<ExtractedFile> extractEmbeddedImagesFromPpt(AbstractFile af) {
List<XWPFPictureData> 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<ExtractedImage> 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<ExtractedImage> extractImagesFromPpt(AbstractFile af) {
List<HSLFPictureData> listOfAllPictures = null; List<HSLFPictureData> listOfAllPictures = null;
try { try {
HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af)); HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
listOfAllPictures = ppt.getPictureData(); listOfAllPictures = ppt.getPictureData();
} catch (IOException | IllegalArgumentException | } catch (IOException | IllegalArgumentException
IndexOutOfBoundsException ex) { | IndexOutOfBoundsException ex) {
// IllegalArgumentException: // IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the // This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may // document version is unsupported. The IllegalArgumentException may
// also get thrown for unknown reasons. // also get thrown for unknown reasons.
// IOException: // IOException:
// Thrown when the document has issues being read. // Thrown when the document has issues being read.
// IndexOutOfBoundsException: // IndexOutOfBoundsException:
// This gets thrown in certain images. The reason is unknown. It is // This gets thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly // likely due to problems with the file formats that POI is poorly
// handling. // handling.
return null; return null;
} catch (Throwable ex) { } catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions // 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; return null;
} }
@ -374,10 +367,10 @@ class ImageExtractor {
return null; return null;
} }
// extract the images to the above initialized outputFolder. // extract the content to the above initialized outputFolder.
// extraction path - outputFolder/image_number.ext // extraction path - outputFolder/image_number.ext
int i = 0; int i = 0;
List<ExtractedImage> listOfExtractedImages = new ArrayList<>(); List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
byte[] data = null; byte[] data = null;
for (HSLFPictureData pictureData : listOfAllPictures) { for (HSLFPictureData pictureData : listOfAllPictures) {
@ -404,80 +397,19 @@ class ImageExtractor {
default: default:
continue; continue;
} }
String imageName = UNKNOWN_NAME_PREFIX + i + ext; //NON-NLS String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + ext; //NON-NLS
try { try {
data = pictureData.getData(); data = pictureData.getData();
} catch (Exception ex) { } catch (Exception ex) {
return null; return null;
} }
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data); 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++; i++;
} }
return listOfExtractedImages; 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<ExtractedImage> extractImagesFromPptx(AbstractFile af) {
List<XSLFPictureData> 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<ExtractedImage> 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. * Extract images from xls format files.
* *
@ -486,41 +418,37 @@ class ImageExtractor {
* @return list of extracted images. Returns null in case no images were * @return list of extracted images. Returns null in case no images were
* extracted. * extracted.
*/ */
private List<ExtractedImage> extractImagesFromXls(AbstractFile af) { private List<ExtractedFile> extractImagesFromXls(AbstractFile af) {
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null; List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
try { try {
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af)); Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
listOfAllPictures = xls.getAllPictures(); listOfAllPictures = xls.getAllPictures();
} catch (IOException | LeftoverDataException | } catch (IOException | LeftoverDataException
RecordFormatException | IllegalArgumentException | | RecordFormatException | IllegalArgumentException
IndexOutOfBoundsException ex) { | IndexOutOfBoundsException ex) {
// IllegalArgumentException: // IllegalArgumentException:
// This will catch OldFileFormatException, which is thrown when the // This will catch OldFileFormatException, which is thrown when the
// document version is unsupported. The IllegalArgumentException may // document version is unsupported. The IllegalArgumentException may
// also get thrown for unknown reasons. // also get thrown for unknown reasons.
// IOException: // IOException:
// Thrown when the document has issues being read. // Thrown when the document has issues being read.
// LeftoverDataException: // LeftoverDataException:
// This is thrown for poorly formatted files that have more data // This is thrown for poorly formatted files that have more data
// than expected. // than expected.
// RecordFormatException: // RecordFormatException:
// This is thrown for poorly formatted files that have less data // This is thrown for poorly formatted files that have less data
// that expected. // that expected.
// IllegalArgumentException: // IllegalArgumentException:
// IndexOutOfBoundsException: // IndexOutOfBoundsException:
// These get thrown in certain images. The reason is unknown. It is // These get thrown in certain images. The reason is unknown. It is
// likely due to problems with the file formats that POI is poorly // likely due to problems with the file formats that POI is poorly
// handling. // handling.
return null; return null;
} catch (Throwable ex) { } catch (Throwable ex) {
// instantiating POI containers throw RuntimeExceptions // 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; return null;
} }
@ -537,75 +465,17 @@ class ImageExtractor {
} }
int i = 0; int i = 0;
List<ExtractedImage> listOfExtractedImages = new ArrayList<>(); List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
byte[] data = null; byte[] data = null;
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) { 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 { try {
data = pictureData.getData(); data = pictureData.getData();
} catch (Exception ex) { } catch (Exception ex) {
return null; return null;
} }
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data); 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 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<ExtractedImage> 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<ExtractedImage> 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));
i++; i++;
} }
return listOfExtractedImages; return listOfExtractedImages;
@ -623,18 +493,17 @@ class ImageExtractor {
try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) { try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) {
fos.write(data); fos.write(data);
} catch (IOException ex) { } 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. * exist, it is created.
* *
* @param parentFileName name of the abstract file being processed for image * @param parentFileName name of the abstract file being processed
* extraction.
* *
* @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) { private String getOutputFolderPath(String parentFileName) {
String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName; String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName;
@ -643,7 +512,7 @@ class ImageExtractor {
try { try {
outputFilePath.mkdirs(); outputFilePath.mkdirs();
} catch (SecurityException ex) { } 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; return null;
} }
} }
@ -665,11 +534,11 @@ class ImageExtractor {
} }
/** /**
* Represents the image extracted using POI methods. Currently, POI is not * Represents a file extracted using either Tika or POI methods. Currently,
* capable of extracting ctime, crtime, mtime, and atime; these values are * POI is not capable of extracting ctime, crtime, mtime, and atime; these
* set to 0. * values are set to 0.
*/ */
private static class ExtractedImage { private static class ExtractedFile {
//String fileName, String localPath, long size, long ctime, long crtime, //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 //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 crtime;
private final long atime; private final long atime;
private final long mtime; private final long mtime;
private final AbstractFile parentFile;
ExtractedImage(String fileName, String localPath, long size, AbstractFile parentFile) { ExtractedFile(String fileName, String localPath, long size) {
this(fileName, localPath, size, 0, 0, 0, 0, parentFile); 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.fileName = fileName;
this.localPath = localPath; this.localPath = localPath;
this.size = size; this.size = size;
@ -694,7 +562,6 @@ class ImageExtractor {
this.crtime = crtime; this.crtime = crtime;
this.atime = atime; this.atime = atime;
this.mtime = mtime; this.mtime = mtime;
this.parentFile = parentFile;
} }
public String getFileName() { public String getFileName() {
@ -724,9 +591,84 @@ class ImageExtractor {
public long getMtime() { public long getMtime() {
return mtime; 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<String, ExtractedFile> 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<ExtractedFile> getExtractedImages() {
return new ArrayList<>(nameToExtractedFileMap.values());
} }
} }
} }

View File

@ -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

View File

@ -45,8 +45,11 @@ import org.sleuthkit.datamodel.TskData;
*/ */
final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter { final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
private static final double ENTROPY_THRESHOLD = 7.5; static final double DEFAULT_CONFIG_MINIMUM_ENTROPY = 7.5;
private static final int FILE_SIZE_THRESHOLD = 5242880; // 5MB 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 int FILE_SIZE_MODULUS = 512;
private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2)) private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2))
private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256; private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
@ -55,13 +58,24 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName()); private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName());
private FileTypeDetector fileTypeDetector; private FileTypeDetector fileTypeDetector;
private Blackboard blackboard; private Blackboard blackboard;
private double entropy; 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 * Create a EncryptionDetectionFileIngestModule object that will detect
* that are encrypted and create blackboard artifacts as appropriate. * files that are encrypted and create blackboard artifacts as appropriate.
* The supplied EncryptionDetectionIngestJobSettings object is used to
* configure the module.
*/ */
EncryptionDetectionFileIngestModule() { EncryptionDetectionFileIngestModule(EncryptionDetectionIngestJobSettings settings) {
minimumEntropy = settings.getMinimumEntropy();
minimumFileSize = settings.getMinimumFileSize();
fileSizeMultipleEnforced = settings.isFileSizeMultipleEnforced();
slackFilesAllowed = settings.isSlackFilesAllowed();
} }
@Override @Override
@ -120,7 +134,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
*/ */
StringBuilder detailsSb = new StringBuilder(); StringBuilder detailsSb = new StringBuilder();
detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("<br/>\n"); detailsSb.append("File: ").append(file.getParentPath()).append(file.getName()).append("<br/>\n");
detailsSb.append("Entropy: ").append(entropy); detailsSb.append("Entropy: ").append(calculatedEntropy);
SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(), SERVICES.postMessage(IngestMessage.createDataMessage(EncryptionDetectionModuleFactory.getModuleName(),
"Encryption Detected Match: " + file.getName(), "Encryption Detected Match: " + file.getName(),
@ -159,7 +173,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
if (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) 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.UNUSED_BLOCKS)
&& !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR) && !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.LOCAL_DIR)
&& (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed)) {
/* /*
* Qualify the file against hash databases. * Qualify the file against hash databases.
*/ */
@ -168,17 +183,19 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
* Qualify the size. * Qualify the size.
*/ */
long contentSize = file.getSize(); long contentSize = file.getSize();
if (contentSize >= FILE_SIZE_THRESHOLD && (contentSize % FILE_SIZE_MODULUS) == 0) { if (contentSize >= minimumFileSize) {
/* if (!fileSizeMultipleEnforced || (contentSize % FILE_SIZE_MODULUS) == 0) {
* Qualify the MIME type. /*
*/ * Qualify the MIME type.
try { */
String mimeType = fileTypeDetector.getFileType(file); try {
if (mimeType != null && mimeType.equals("application/octet-stream")) { String mimeType = fileTypeDetector.getFileType(file);
possiblyEncrypted = true; if (mimeType != null && mimeType.equals("application/octet-stream")) {
possiblyEncrypted = true;
}
} catch (TskCoreException ex) {
throw new TskCoreException("Failed to detect the file type.", ex);
} }
} catch (TskCoreException ex) {
throw new TskCoreException("Failed to detect the file type.", ex);
} }
} }
} }
@ -186,8 +203,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
if (possiblyEncrypted) { if (possiblyEncrypted) {
try { try {
entropy = calculateEntropy(file); calculatedEntropy = calculateEntropy(file);
if (entropy > ENTROPY_THRESHOLD) { if (calculatedEntropy >= minimumEntropy) {
return true; return true;
} }
} catch (IOException ex) { } catch (IOException ex) {

View File

@ -0,0 +1,133 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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;
}
}

View File

@ -0,0 +1,132 @@
<?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.9" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_autoSetComponentName" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_generateFQN" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_generateMnemonicsCode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_i18nAutoMode" type="java.lang.Boolean" value="true"/>
<AuxValue name="FormSettings_layoutCodeTarget" type="java.lang.Integer" value="1"/>
<AuxValue name="FormSettings_listenerGenerationStyle" type="java.lang.Integer" value="0"/>
<AuxValue name="FormSettings_variablesLocal" type="java.lang.Boolean" value="false"/>
<AuxValue name="FormSettings_variablesModifier" type="java.lang.Integer" value="2"/>
</AuxValues>
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="slackFilesAllowedCheckbox" min="-2" max="-2" attributes="0"/>
<Component id="detectionSettingsLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Component id="minimumFileSizeLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="minimumFileSizeTextbox" min="-2" pref="32" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="minimumEntropyLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="minimumEntropyTextbox" min="-2" pref="32" max="-2" attributes="0"/>
</Group>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Component id="mbLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="fileSizeMultiplesEnforcedCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace pref="15" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="detectionSettingsLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="16" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="minimumEntropyTextbox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="minimumEntropyLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="minimumFileSizeTextbox" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="mbLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="minimumFileSizeLabel" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="fileSizeMultiplesEnforcedCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="slackFilesAllowedCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace pref="160" max="32767" attributes="0"/>
</Group>
</Group>
</DimensionLayout>
</Layout>
<SubComponents>
<Component class="javax.swing.JTextField" name="minimumEntropyTextbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumEntropyTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="minimumFileSizeTextbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeTextbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="fileSizeMultiplesEnforcedCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.fileSizeMultiplesEnforcedCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JCheckBox" name="slackFilesAllowedCheckbox">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.slackFilesAllowedCheckbox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="minimumEntropyLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumEntropyLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="minimumFileSizeLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.minimumFileSizeLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="mbLabel">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.mbLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JLabel" name="detectionSettingsLabel">
<Properties>
<Property name="font" type="java.awt.Font" editor="org.netbeans.beaninfo.editors.FontEditor">
<Font name="Tahoma" size="11" style="1"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/modules/encryptiondetection/Bundle.properties" key="EncryptionDetectionIngestJobSettingsPanel.detectionSettingsLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
</SubComponents>
</Form>

View File

@ -0,0 +1,201 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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")
// <editor-fold defaultstate="collapsed" desc="Generated Code">//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))
);
}// </editor-fold>//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
}

View File

@ -22,10 +22,12 @@ import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages; import org.openide.util.NbBundle.Messages;
import org.openide.util.lookup.ServiceProvider; import org.openide.util.lookup.ServiceProvider;
import org.sleuthkit.autopsy.coreutils.Version; import org.sleuthkit.autopsy.coreutils.Version;
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
import org.sleuthkit.autopsy.ingest.FileIngestModule; import org.sleuthkit.autopsy.ingest.FileIngestModule;
import org.sleuthkit.autopsy.ingest.IngestModuleFactory; import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter; import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings; import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
/** /**
* A factory that creates file ingest modules that detect encryption. * A factory that creates file ingest modules that detect encryption.
@ -33,9 +35,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
@ServiceProvider(service = IngestModuleFactory.class) @ServiceProvider(service = IngestModuleFactory.class)
@Messages({ @Messages({
"EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection", "EncryptionDetectionFileIngestModule.moduleName.text=Encryption Detection",
"EncryptionDetectionFileIngestModule.getDesc.text=Looks for large files with high entropy." "EncryptionDetectionFileIngestModule.getDesc.text=Looks for files with the specified minimum entropy."
}) })
public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter { public class EncryptionDetectionModuleFactory implements IngestModuleFactory {
@Override @Override
public String getModuleDisplayName() { public String getModuleDisplayName() {
@ -44,7 +46,7 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter
/** /**
* Get the name of the module. * Get the name of the module.
* *
* @return The module name. * @return The module name.
*/ */
static String getModuleName() { static String getModuleName() {
@ -67,7 +69,48 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter
} }
@Override @Override
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) { public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
return new EncryptionDetectionFileIngestModule(); 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();
}
}

View File

@ -18,6 +18,7 @@
*/ */
package org.sleuthkit.autopsy.modules.filetypeid; package org.sleuthkit.autopsy.modules.filetypeid;
import java.io.IOException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collection; import java.util.Collection;
import java.util.Collections; import java.util.Collections;
@ -27,7 +28,9 @@ import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors; import java.util.stream.Collectors;
import org.apache.tika.Tika; import org.apache.tika.Tika;
import org.apache.tika.io.TikaInputStream;
import org.apache.tika.mime.MimeTypes; import org.apache.tika.mime.MimeTypes;
import org.openide.util.Exceptions;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.Blackboard; import org.sleuthkit.autopsy.casemodule.services.Blackboard;
@ -36,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.ReadContentInputStream;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -50,8 +54,6 @@ public class FileTypeDetector {
private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName()); private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName());
private static final Tika tika = new Tika(); 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<FileType> userDefinedFileTypes; private final List<FileType> userDefinedFileTypes;
private final List<FileType> autopsyDefinedFileTypes; private final List<FileType> autopsyDefinedFileTypes;
private static SortedSet<String> tikaDetectedTypes; private static SortedSet<String> tikaDetectedTypes;
@ -270,17 +272,11 @@ public class FileTypeDetector {
* bytes to Tika. * bytes to Tika.
*/ */
if (null == mimeType) { if (null == mimeType) {
try { ReadContentInputStream stream = new ReadContentInputStream(file);
byte buf[];
int len = file.read(buffer, 0, BUFFER_SIZE); try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) {
if (len < BUFFER_SIZE) { String tikaType = tika.detect(tikaInputStream, file.getName());
buf = new byte[len];
System.arraycopy(buffer, 0, buf, 0, len);
} else {
buf = buffer;
}
String tikaType = tika.detect(buf, file.getName());
/* /*
* Remove the Tika suffix from the MIME type name. * Remove the Tika suffix from the MIME type name.
*/ */

View File

@ -17,7 +17,7 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed.
HashDbSearchPanel.saveBox.text=Remember Hashes HashDbSearchPanel.saveBox.text=Remember Hashes
HashDbSearchPanel.cancelButton.text=Cancel HashDbSearchPanel.cancelButton.text=Cancel
OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools 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.databasePathTextField.text=
HashDbImportDatabaseDialog.knownBadRadioButton.text=Notable HashDbImportDatabaseDialog.knownBadRadioButton.text=Notable
HashDbImportDatabaseDialog.jLabel2.text=Type of database\: 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.sendIngestMessagesCheckbox.text=Send ingest inbox message for each hit
HashDbImportDatabaseDialog.hashSetNameTextField.text= HashDbImportDatabaseDialog.hashSetNameTextField.text=
HashDbImportDatabaseDialog.openButton.text=Open... HashDbImportDatabaseDialog.openButton.text=Open...
HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name: HashDbCreateDatabaseDialog.jLabel3.text=Name:
HashDbCreateDatabaseDialog.okButton.text=OK HashDbCreateDatabaseDialog.okButton.text=OK
HashDbCreateDatabaseDialog.databasePathTextField.text= HashDbCreateDatabaseDialog.databasePathTextField.text=
AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured
@ -205,7 +205,7 @@ HashLookupSettingsPanel.typeLabel.text=Type:
HashLookupSettingsPanel.locationLabel.text=Database Path: HashLookupSettingsPanel.locationLabel.text=Database Path:
HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected
HashLookupSettingsPanel.hashDbNameLabel.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.hashDatabasesLabel.text=Hash Databases:
HashLookupSettingsPanel.importDatabaseButton.toolTipText= HashLookupSettingsPanel.importDatabaseButton.toolTipText=
HashLookupSettingsPanel.importDatabaseButton.text=Import database HashLookupSettingsPanel.importDatabaseButton.text=Import database
@ -229,13 +229,13 @@ HashDbImportDatabaseDialog.lbVersion.text=Version:
HashDbImportDatabaseDialog.lbOrg.text=Source Organization: HashDbImportDatabaseDialog.lbOrg.text=Source Organization:
HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only
HashDbImportDatabaseDialog.orgButton.text=Manage Organizations HashDbImportDatabaseDialog.orgButton.text=Manage Organizations
HashDbImportDatabaseDialog.versionTextField.text= HashDbImportDatabaseDialog.versionTextField.text=1.0
HashDbImportDatabaseDialog.fileTypeRadioButton.text=File HashDbImportDatabaseDialog.fileTypeRadioButton.text=Local
HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository HashDbImportDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository)
HashDbImportDatabaseDialog.jLabel4.text=Location: HashDbImportDatabaseDialog.jLabel4.text=Destination:
HashDbCreateDatabaseDialog.jLabel4.text=Location: HashDbCreateDatabaseDialog.jLabel4.text=Destination:
HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File HashDbCreateDatabaseDialog.fileTypeRadioButton.text=Local
HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository)
HashDbCreateDatabaseDialog.lbOrg.text=Source Organization: HashDbCreateDatabaseDialog.lbOrg.text=Source Organization:
HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations
HashDbCreateDatabaseDialog.databasePathLabel.text=Database Path: HashDbCreateDatabaseDialog.databasePathLabel.text=Database Path:

View File

@ -33,6 +33,7 @@ import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; 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.EamOrganization;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet; import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet;
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
@ -154,8 +155,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
orgs = dbManager.getOrganizations(); orgs = dbManager.getOrganizations();
orgs.forEach((org) -> { orgs.forEach((org) -> {
orgComboBox.addItem(org.getName()); 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); selectedOrg = orgs.get(0);
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {

View File

@ -33,17 +33,37 @@
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace min="0" pref="325" max="32767" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Component id="okButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="fileTypeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="centralRepoRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
</Group>
<Group type="102" attributes="0">
<Component id="databasePathTextField" max="32767" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="openButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
</Group>
</Group>
</Group> </Group>
<Group type="102" alignment="1" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="1" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0">
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/>
<Component id="okButton" linkSize="1" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0"> <Group type="102" alignment="1" attributes="0">
<Component id="lbOrg" min="-2" max="-2" attributes="0"/> <Component id="lbOrg" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="orgComboBox" max="32767" attributes="0"/> <Component id="orgComboBox" pref="121" max="32767" attributes="0"/>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="orgButton" min="-2" max="-2" attributes="0"/> <Component id="orgButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
@ -52,96 +72,87 @@
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="lbVersion" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="lbVersion" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/> <EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="1" attributes="0">
<Component id="versionTextField" max="32767" attributes="0"/> <Component id="versionTextField" max="32767" attributes="0"/>
<Component id="hashSetNameTextField" max="32767" attributes="0"/> <Component id="hashSetNameTextField" max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel3" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Component id="fileTypeRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
<Component id="centralRepoRadioButton" min="-2" max="-2" attributes="0"/>
</Group>
<Component id="databasePathTextField" max="32767" attributes="0"/>
</Group>
</Group>
</Group> </Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/>
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="openButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/> <Component id="jLabel2" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" alignment="0" attributes="0"> <Component id="readOnlyCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Group type="102" attributes="0">
<EmptySpace min="-2" pref="19" max="-2" attributes="0"/> <EmptySpace min="-2" pref="19" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/> <Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/> <Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
<Component id="sendIngestMessagesCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="readOnlyCheckbox" alignment="0" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace min="0" pref="0" max="32767" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
</Group> </Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/>
</Group> </Group>
</Group> </Group>
</DimensionLayout> </DimensionLayout>
<DimensionLayout dim="1"> <DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="1" attributes="0"> <Group type="102" attributes="0">
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="fileTypeRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="centralRepoRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="openButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="databasePathTextField" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="databasePathTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="openButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/> <Group type="102" attributes="0">
<Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="3" attributes="0">
</Group> <Component id="fileTypeRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <Component id="centralRepoRadioButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Component id="jLabel4" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="versionTextField" alignment="3" min="-2" max="-2" attributes="0"/> </Group>
<Component id="lbVersion" alignment="3" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> <Group type="103" groupAlignment="3" attributes="0">
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/> <Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="orgButton" alignment="3" min="-2" max="-2" attributes="0"/> </Group>
<Component id="orgComboBox" alignment="3" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="lbOrg" alignment="3" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="3" attributes="0">
</Group> <Component id="lbVersion" alignment="3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <Component id="versionTextField" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="jLabel2" min="-2" max="-2" attributes="0"/> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/> <Group type="103" groupAlignment="3" attributes="0">
<EmptySpace max="-2" attributes="0"/> <Component id="orgButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/> <Component id="orgComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/> <Component id="lbOrg" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="readOnlyCheckbox" min="-2" max="-2" attributes="0"/> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/> <Component id="jLabel2" min="-2" max="-2" attributes="0"/>
<EmptySpace max="32767" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="readOnlyCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
<Component id="sendIngestMessagesCheckbox" min="-2" max="-2" attributes="0"/>
<EmptySpace min="0" pref="21" max="32767" attributes="0"/>
</Group>
<Group type="102" alignment="1" attributes="0">
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0">
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group> </Group>
<EmptySpace max="-2" attributes="0"/> <EmptySpace max="-2" attributes="0"/>
</Group> </Group>

View File

@ -34,6 +34,7 @@ import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb; import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException; 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.EamOrganization;
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog; import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -84,25 +85,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
private void initFileChooser() { private void initFileChooser() {
fileChooser.setDragEnabled(false); fileChooser.setDragEnabled(false);
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY); 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); fileChooser.setMultiSelectionEnabled(false);
} }
@NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.kdb, .idx or .hash)"})
private void updateFileChooserFilter() {
fileChooser.resetChoosableFileFilters();
if(centralRepoRadioButton.isSelected()){
String[] EXTENSION = new String[]{"kdb", "idx", "hash", "Hash"}; //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() { private void display() {
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
@ -148,8 +136,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
orgs = dbManager.getOrganizations(); orgs = dbManager.getOrganizations();
orgs.forEach((org) -> { orgs.forEach((org) -> {
orgComboBox.addItem(org.getName()); 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); selectedOrg = orgs.get(0);
} }
} catch (EamDbException ex) { } catch (EamDbException ex) {
@ -303,95 +295,102 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(0, 325, Short.MAX_VALUE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(okButton) .addComponent(jLabel3)
.addComponent(jLabel4))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addGroup(layout.createSequentialGroup() .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) .addComponent(lbOrg)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .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) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addComponent(orgButton)) .addComponent(orgButton))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel1) .addComponent(jLabel1)
.addComponent(lbVersion)) .addComponent(lbVersion))
.addGap(2, 2, 2) .addGap(40, 40, 40)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
.addComponent(versionTextField) .addComponent(versionTextField)
.addComponent(hashSetNameTextField))) .addComponent(hashSetNameTextField))))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addComponent(cancelButton)
.addComponent(jLabel3) .addContainerGap())
.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))
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabel2) .addComponent(jLabel2)
.addComponent(readOnlyCheckbox)
.addGroup(layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addGap(19, 19, 19) .addGap(19, 19, 19)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(knownRadioButton) .addComponent(knownRadioButton)
.addComponent(knownBadRadioButton))) .addComponent(knownBadRadioButton))))
.addComponent(sendIngestMessagesCheckbox) .addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
.addComponent(readOnlyCheckbox))
.addGap(0, 0, Short.MAX_VALUE)))
.addContainerGap())
); );
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton}); layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
layout.setVerticalGroup( layout.setVerticalGroup(
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup() .addGroup(layout.createSequentialGroup()
.addContainerGap() .addContainerGap()
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .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(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(jLabel3)) .addComponent(jLabel3)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(openButton))
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGap(18, 18, 18)
.addComponent(jLabel1) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)) .addGroup(layout.createSequentialGroup()
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(fileTypeRadioButton)
.addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(centralRepoRadioButton)
.addComponent(lbVersion)) .addComponent(jLabel4))
.addGap(9, 9, 9) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(orgButton) .addComponent(jLabel1)
.addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(lbOrg)) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(jLabel2) .addComponent(lbVersion)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(knownRadioButton) .addGap(5, 5, 5)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(knownBadRadioButton) .addComponent(orgButton)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
.addComponent(readOnlyCheckbox) .addComponent(lbOrg))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(sendIngestMessagesCheckbox) .addComponent(jLabel2)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addComponent(knownRadioButton)
.addComponent(okButton) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(cancelButton)) .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()) .addContainerGap())
); );
@ -409,7 +408,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
hashDbFolder.mkdir(); hashDbFolder.mkdir();
} }
fileChooser.setCurrentDirectory(hashDbFolder); fileChooser.setCurrentDirectory(hashDbFolder);
updateFileChooserFilter();
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
File databaseFile = fileChooser.getSelectedFile(); File databaseFile = fileChooser.getSelectedFile();
try { try {

View File

@ -105,28 +105,6 @@
<Group type="102" attributes="0"> <Group type="102" attributes="0">
<EmptySpace min="10" pref="10" max="-2" attributes="0"/> <EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="locationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="typeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="versionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="orgLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="readOnlyLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="55" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashDbTypeLabel" min="-2" pref="225" max="-2" attributes="0"/>
<Component id="hashDbLocationLabel" alignment="0" min="-2" pref="225" max="-2" attributes="0"/>
<Component id="hashDbVersionLabel" min="-2" max="-2" attributes="0"/>
<Component id="hashDbOrgLabel" min="-2" max="-2" attributes="0"/>
<Component id="hashDbReadOnlyLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
<Group type="102" alignment="0" attributes="0">
<Component id="nameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="53" max="-2" attributes="0"/>
<Component id="hashDbNameLabel" min="-2" max="-2" attributes="0"/>
</Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0"> <Group type="103" groupAlignment="0" attributes="0">
<Component id="indexLabel" alignment="0" min="-2" pref="66" max="-2" attributes="0"/> <Component id="indexLabel" alignment="0" min="-2" pref="66" max="-2" attributes="0"/>
@ -143,6 +121,25 @@
<EmptySpace min="10" pref="10" max="-2" attributes="0"/> <EmptySpace min="10" pref="10" max="-2" attributes="0"/>
<Component id="addHashesToDatabaseButton" min="-2" max="-2" attributes="0"/> <Component id="addHashesToDatabaseButton" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<Group type="102" alignment="0" attributes="0">
<Group type="103" groupAlignment="0" attributes="0">
<Component id="locationLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="typeLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="versionLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="orgLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="readOnlyLabel" alignment="0" min="-2" max="-2" attributes="0"/>
<Component id="nameLabel" alignment="0" min="-2" max="-2" attributes="0"/>
</Group>
<EmptySpace min="-2" pref="55" max="-2" attributes="0"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="hashDbNameLabel" min="-2" max="-2" attributes="0"/>
<Component id="hashDbTypeLabel" min="-2" pref="225" max="-2" attributes="0"/>
<Component id="hashDbLocationLabel" alignment="0" min="-2" pref="225" max="-2" attributes="0"/>
<Component id="hashDbVersionLabel" min="-2" max="-2" attributes="0"/>
<Component id="hashDbOrgLabel" min="-2" max="-2" attributes="0"/>
<Component id="hashDbReadOnlyLabel" min="-2" max="-2" attributes="0"/>
</Group>
</Group>
</Group> </Group>
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">

View File

@ -787,24 +787,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10) .addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .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.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING) .addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE)
@ -816,7 +798,23 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
.addGroup(jPanel1Layout.createSequentialGroup() .addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE) .addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
.addGap(10, 10, 10) .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() .addGroup(jPanel1Layout.createSequentialGroup()
.addGap(70, 70, 70) .addGap(70, 70, 70)
.addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE))

View File

@ -0,0 +1,133 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> 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<CSVRecord> 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;
}
}
}
}

View File

@ -28,7 +28,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Parser for idx files (*.idx) * 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 { class IdxHashSetParser implements HashSetParser {
@ -49,6 +50,7 @@ class IdxHashSetParser implements HashSetParser {
File importFile = new File(filename); File importFile = new File(filename);
long fileSize = importFile.length(); 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 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)
} }
/** /**
@ -65,14 +67,15 @@ class IdxHashSetParser implements HashSetParser {
try { try {
while ((line = reader.readLine()) != null) { while ((line = reader.readLine()) != null) {
String[] parts = line.split("\\|"); // idx files have a pipe after the hash, md5sum files should have a space
String[] parts = line.split("\\|| ");
// Header lines start with a 41 character dummy hash, 1 character longer than a SHA-1 hash String hashStr = parts[0].toLowerCase();
if (parts.length != 2 || parts[0].length() == 41) { if (!hashStr.matches("^[0-9a-f]{32}$")) {
continue; continue;
} }
return parts[0].toLowerCase(); return hashStr;
} }
} catch (IOException ex) { } catch (IOException ex) {
throw new TskCoreException("Error reading file " + filename, ex); throw new TskCoreException("Error reading file " + filename, ex);

View File

@ -213,12 +213,14 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P
// Create the hash set parser // Create the hash set parser
HashSetParser hashSetParser; HashSetParser hashSetParser;
if (importFileName.toLowerCase().endsWith(".idx")) { if (importFileName.toLowerCase().endsWith(".idx") || importFileName.toLowerCase().endsWith(".txt")) {
hashSetParser = new IdxHashSetParser(importFileName); hashSetParser = new IdxHashSetParser(importFileName);
} else if(importFileName.toLowerCase().endsWith(".hash")){ } else if (importFileName.toLowerCase().endsWith(".hash")) {
hashSetParser = new EncaseHashSetParser(importFileName); hashSetParser = new EncaseHashSetParser(importFileName);
} else if(importFileName.toLowerCase().endsWith(".kdb")){ } else if (importFileName.toLowerCase().endsWith(".kdb")) {
hashSetParser = new KdbHashSetParser(importFileName); hashSetParser = new KdbHashSetParser(importFileName);
} else if (importFileName.toLowerCase().endsWith(".hsh")) {
hashSetParser = new HashkeeperHashSetParser(importFileName);
} else { } else {
// We've gotten here with a format that can't be processed // We've gotten here with a format that can't be processed
throw new TskCoreException("Hash set to import is an unknown format : " + importFileName); throw new TskCoreException("Hash set to import is an unknown format : " + importFileName);

View File

@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
class ReportHTML implements TableReportModule { class ReportHTML implements TableReportModule {
@ -688,7 +689,8 @@ class ReportHTML implements TableReportModule {
} }
for (int i = 0; i < tags.size(); i++) { for (int i = 0; i < tags.size(); i++) {
ContentTag tag = tags.get(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) { if (i != tags.size() - 1) {
linkToThumbnail.append(", "); linkToThumbnail.append(", ");
} }

View File

@ -41,10 +41,12 @@ import javax.swing.event.ListDataListener;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
final class ReportVisualPanel2 extends JPanel { final class ReportVisualPanel2 extends JPanel {
@ -102,7 +104,8 @@ final class ReportVisualPanel2 extends JPanel {
} }
for (TagName tagName : tagNamesInUse) { 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()); tags.addAll(tagStates.keySet());

View File

@ -39,6 +39,7 @@ import java.util.TreeSet;
import java.util.logging.Level; import java.util.logging.Level;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.EscapeUtil; import org.sleuthkit.autopsy.coreutils.EscapeUtil;
import org.sleuthkit.autopsy.coreutils.ImageUtils; import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
@ -299,7 +300,8 @@ class TableReportGenerator {
// Give the modules the rows for the content tags. // Give the modules the rows for the content tags.
for (ContentTag tag : tags) { for (ContentTag tag : tags) {
// skip tags that we are not reporting on // 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; continue;
} }
@ -310,7 +312,7 @@ class TableReportGenerator {
fileName = tag.getContent().getName(); fileName = tag.getContent().getName();
} }
ArrayList<String> rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName(), fileName, tag.getComment())); ArrayList<String> rowData = new ArrayList<>(Arrays.asList(tag.getName().getDisplayName() + notableString, fileName, tag.getComment()));
Content content = tag.getContent(); Content content = tag.getContent();
if (content instanceof AbstractFile) { if (content instanceof AbstractFile) {
AbstractFile file = (AbstractFile) content; AbstractFile file = (AbstractFile) content;
@ -376,12 +378,13 @@ class TableReportGenerator {
// Give the modules the rows for the content tags. // Give the modules the rows for the content tags.
for (BlackboardArtifactTag tag : 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; continue;
} }
List<String> row; List<String> 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); tableReport.addRow(row);
// check if the tag is an image that we should later make a thumbnail for // check if the tag is an image that we should later make a thumbnail for
@ -963,7 +966,8 @@ class TableReportGenerator {
try { try {
List<ContentTag> contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content); List<ContentTag> contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content);
for (ContentTag ct : contentTags) { 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) { } catch (TskCoreException ex) {
errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags")); errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags"));
@ -1000,7 +1004,8 @@ class TableReportGenerator {
List<BlackboardArtifactTag> tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact); List<BlackboardArtifactTag> tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact);
HashSet<String> uniqueTagNames = new HashSet<>(); HashSet<String> uniqueTagNames = new HashSet<>();
for (BlackboardArtifactTag tag : tags) { 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)) { if (failsTagFilter(uniqueTagNames, tagNamesFilter)) {
continue; continue;

View File

@ -38,10 +38,10 @@ import org.sleuthkit.autopsy.ingest.IngestJob;
* ingest service. * ingest service.
*/ */
@ThreadSafe @ThreadSafe
public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable { final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializable {
private static final long serialVersionUID = 1L; 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 int DEFAULT_PRIORITY = 0;
private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName(); private static final String LOCAL_HOST_NAME = NetworkUtils.getLocalHostName();
@ -82,6 +82,12 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
private int numberOfCrashes; private int numberOfCrashes;
@GuardedBy("this") @GuardedBy("this")
private StageDetails stageDetails; private StageDetails stageDetails;
/*
* Version 2 fields.
*/
@GuardedBy("this")
private long dataSourceSize;
/** /**
* Constructs a new automated ingest job. All job state not specified in the * Constructs a new automated ingest job. All job state not specified in the
@ -114,6 +120,11 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
this.processingStatus = ProcessingStatus.PENDING; this.processingStatus = ProcessingStatus.PENDING;
this.numberOfCrashes = 0; this.numberOfCrashes = 0;
this.stageDetails = this.getProcessingStageDetails(); this.stageDetails = this.getProcessingStageDetails();
/*
* Version 2 fields.
*/
this.dataSourceSize = 0;
} catch (Exception ex) { } catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex); throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
} }
@ -151,6 +162,11 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
this.processingStatus = nodeData.getProcessingStatus(); this.processingStatus = nodeData.getProcessingStatus();
this.numberOfCrashes = nodeData.getNumberOfCrashes(); this.numberOfCrashes = nodeData.getNumberOfCrashes();
this.stageDetails = this.getProcessingStageDetails(); this.stageDetails = this.getProcessingStageDetails();
/*
* Version 2 fields.
*/
this.dataSourceSize = nodeData.getDataSourceSize();
} catch (Exception ex) { } catch (Exception ex) {
throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex); throw new AutoIngestJobException(String.format("Error creating automated ingest job"), ex);
} }
@ -462,6 +478,24 @@ public final class AutoIngestJob implements Comparable<AutoIngestJob>, Serializa
this.numberOfCrashes = numberOfCrashes; 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 * Indicates whether some other job is "equal to" this job. Two jobs are
* equal if they have the same manifest file path. * equal if they have the same manifest file path.

View File

@ -31,7 +31,7 @@ import javax.lang.model.type.TypeKind;
*/ */
final class AutoIngestJobNodeData { final class AutoIngestJobNodeData {
private static final int CURRENT_VERSION = 1; private static final int CURRENT_VERSION = 2;
private static final int DEFAULT_PRIORITY = 0; 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 * data. This avoids the need to continuously enlarge the buffer. Once the
* buffer has all the necessary data, it will be resized as appropriate. * 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. * Version 0 fields.
@ -73,6 +73,11 @@ final class AutoIngestJobNodeData {
private long processingStageStartDate; private long processingStageStartDate;
private String processingStageDetailsDescription; // 'byte' length used in byte array private String processingStageDetailsDescription; // 'byte' length used in byte array
private long processingStageDetailsStartDate; private long processingStageDetailsStartDate;
/*
* Version 2 fields.
*/
private long dataSourceSize;
/** /**
* Gets the current version of the auto ingest job coordination service node * Gets the current version of the auto ingest job coordination service node
@ -109,6 +114,7 @@ final class AutoIngestJobNodeData {
setProcessingStage(job.getProcessingStage()); setProcessingStage(job.getProcessingStage());
setProcessingStageStartDate(job.getProcessingStageStartDate()); setProcessingStageStartDate(job.getProcessingStageStartDate());
setProcessingStageDetails(job.getProcessingStageDetails()); setProcessingStageDetails(job.getProcessingStageDetails());
setDataSourceSize(job.getDataSourceSize());
} }
/** /**
@ -143,6 +149,7 @@ final class AutoIngestJobNodeData {
this.processingStageStartDate = 0L; this.processingStageStartDate = 0L;
this.processingStageDetailsDescription = ""; this.processingStageDetailsDescription = "";
this.processingStageDetailsStartDate = 0L; this.processingStageDetailsStartDate = 0L;
this.dataSourceSize = 0L;
/* /*
* Get fields from node data. * Get fields from node data.
@ -179,6 +186,13 @@ final class AutoIngestJobNodeData {
this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT); this.processingHostName = getStringFromBuffer(buffer, TypeKind.SHORT);
} }
if (buffer.hasRemaining()) {
/*
* Get version 2 fields.
*/
this.dataSourceSize = buffer.getLong();
}
} catch (BufferUnderflowException ex) { } catch (BufferUnderflowException ex) {
throw new InvalidDataException("Node data is incomplete", ex); throw new InvalidDataException("Node data is incomplete", ex);
} }
@ -498,6 +512,24 @@ final class AutoIngestJobNodeData {
void setProcessingHostName(String processingHost) { void setProcessingHostName(String processingHost) {
this.processingHostName = 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 * 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.putLong(this.completedDate);
buffer.putInt(this.errorsOccurred ? 1 : 0); buffer.putInt(this.errorsOccurred ? 1 : 0);
if (this.version > 0) { if (this.version >= 1) {
// Write version // Write version
buffer.putInt(this.version); buffer.putInt(this.version);
@ -531,6 +563,10 @@ final class AutoIngestJobNodeData {
putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE); putStringIntoBuffer(this.processingStageDetailsDescription, buffer, TypeKind.BYTE);
buffer.putLong(this.processingStageDetailsStartDate); buffer.putLong(this.processingStageDetailsStartDate);
putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT); putStringIntoBuffer(processingHostName, buffer, TypeKind.SHORT);
if (this.version >= 2) {
buffer.putLong(this.dataSourceSize);
}
} }
// Prepare the array // Prepare the array

View File

@ -56,7 +56,6 @@ import java.util.concurrent.Future;
import java.util.concurrent.ScheduledThreadPoolExecutor; import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.TimeUnit; import java.util.concurrent.TimeUnit;
import java.util.logging.Level; import java.util.logging.Level;
import java.util.stream.Collectors;
import javax.annotation.concurrent.GuardedBy; import javax.annotation.concurrent.GuardedBy;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case; 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.IngestJobStartResult;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.autopsy.ingest.IngestModuleError; 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 * An auto ingest manager is responsible for processing auto ingest jobs defined
@ -2263,6 +2265,7 @@ final class AutoIngestManager extends Observable implements PropertyChangeListen
return; return;
} }
collectMetrics(caseForJob.getSleuthkitCase(), dataSource);
exportFiles(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<Content> 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 * Exports any files from the data source for the current job that
* satisfy any user-defined file export rules. * satisfy any user-defined file export rules.

View File

@ -1,15 +1,15 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-16 Basis Technology Corp. * Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * 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.Action;
import org.controlsfx.control.action.ActionUtils; import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.NbBundle.Messages;
import org.openide.windows.TopComponent; import org.openide.windows.TopComponent;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog; import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
import org.sleuthkit.autopsy.actions.GetTagNameDialog; import org.sleuthkit.autopsy.actions.GetTagNameDialog;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent; 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.autopsy.imagegallery.datamodel.DrawableTagsManager;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
/** /**
@ -67,7 +70,8 @@ public class AddTagAction extends Action {
this.selectedFileIDs = selectedFileIDs; this.selectedFileIDs = selectedFileIDs;
this.tagName = tagName; this.tagName = tagName;
setGraphic(controller.getTagsManager().getGraphic(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("")); setEventHandler(actionEvent -> addTagWithComment(""));
} }
@ -78,7 +82,7 @@ public class AddTagAction extends Action {
private void addTagWithComment(String comment) { private void addTagWithComment(String comment) {
addTagsToFiles(tagName, comment, selectedFileIDs); addTagsToFiles(tagName, comment, selectedFileIDs);
} }
@NbBundle.Messages({"# {0} - fileID", @NbBundle.Messages({"# {0} - fileID",
"AddDrawableTagAction.addTagsToFiles.alert=Unable to tag file {0}."}) "AddDrawableTagAction.addTagsToFiles.alert=Unable to tag file {0}."})
private void addTagsToFiles(TagName tagName, String comment, Set<Long> selectedFiles) { private void addTagsToFiles(TagName tagName, String comment, Set<Long> selectedFiles) {
@ -108,8 +112,8 @@ public class AddTagAction extends Action {
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error tagging file", tskCoreException); //NON-NLS LOGGER.log(Level.SEVERE, "Error tagging file", tskCoreException); //NON-NLS
Platform.runLater(() -> Platform.runLater(()
new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show() -> new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show()
); );
break; break;
} }
@ -172,8 +176,8 @@ public class AddTagAction extends Action {
* or select a tag name and adds a tag with the resulting name. * or select a tag name and adds a tag with the resulting name.
*/ */
MenuItem newTagMenuItem = new MenuItem(Bundle.AddTagAction_menuItem_newTag()); MenuItem newTagMenuItem = new MenuItem(Bundle.AddTagAction_menuItem_newTag());
newTagMenuItem.setOnAction(actionEvent -> newTagMenuItem.setOnAction(actionEvent
SwingUtilities.invokeLater(() -> { -> SwingUtilities.invokeLater(() -> {
TagName tagName = GetTagNameDialog.doDialog(getIGWindow()); TagName tagName = GetTagNameDialog.doDialog(getIGWindow());
if (tagName != null) { if (tagName != null) {
new AddTagAction(controller, tagName, selectedFileIDs).handle(actionEvent); new AddTagAction(controller, tagName, selectedFileIDs).handle(actionEvent);
@ -188,8 +192,8 @@ public class AddTagAction extends Action {
* name. * name.
*/ */
MenuItem tagAndCommentItem = new MenuItem(Bundle.AddTagAction_menuItem_tagAndComment()); MenuItem tagAndCommentItem = new MenuItem(Bundle.AddTagAction_menuItem_tagAndComment());
tagAndCommentItem.setOnAction(actionEvent -> tagAndCommentItem.setOnAction(actionEvent
SwingUtilities.invokeLater(() -> { -> SwingUtilities.invokeLater(() -> {
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(getIGWindow()); GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(getIGWindow());
if (null != tagNameAndComment) { if (null != tagNameAndComment) {
new AddTagAction(controller, tagNameAndComment.getTagName(), selectedFileIDs).addTagWithComment(tagNameAndComment.getComment()); new AddTagAction(controller, tagNameAndComment.getTagName(), selectedFileIDs).addTagWithComment(tagNameAndComment.getComment());

View File

@ -1,15 +1,15 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2017 Basis Technology Corp. * Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License. * you may not use this file except in compliance with the License.
* You may obtain a copy of the License at * You may obtain a copy of the License at
* *
* http://www.apache.org/licenses/LICENSE-2.0 * http://www.apache.org/licenses/LICENSE-2.0
* *
* Unless required by applicable law or agreed to in writing, software * Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS, * distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -18,7 +18,6 @@
*/ */
package org.sleuthkit.autopsy.imagegallery.actions; package org.sleuthkit.autopsy.imagegallery.actions;
import java.awt.Window;
import java.util.Collection; import java.util.Collection;
import java.util.HashSet; import java.util.HashSet;
import java.util.Iterator; import java.util.Iterator;
@ -30,24 +29,22 @@ import javafx.scene.control.Alert;
import javafx.scene.control.Menu; import javafx.scene.control.Menu;
import javafx.scene.control.MenuItem; import javafx.scene.control.MenuItem;
import javafx.scene.image.ImageView; import javafx.scene.image.ImageView;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker; import javax.swing.SwingWorker;
import org.controlsfx.control.action.Action; import org.controlsfx.control.action.Action;
import org.controlsfx.control.action.ActionUtils; import org.controlsfx.control.action.ActionUtils;
import org.openide.util.NbBundle; import org.openide.util.NbBundle;
import org.openide.util.Utilities; 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.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController; 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.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager; import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData;
/** /**
* Instances of this Action allow users to remove tags from content. * Instances of this Action allow users to remove tags from content.
@ -68,7 +65,8 @@ public class DeleteTagAction extends Action {
this.tagName = tagName; this.tagName = tagName;
this.contentTag = contentTag; this.contentTag = contentTag;
setGraphic(controller.getTagsManager().getGraphic(tagName)); setGraphic(controller.getTagsManager().getGraphic(tagName));
setText(tagName.getDisplayName()); String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
setText(tagName.getDisplayName() + notableString);
setEventHandler(actionEvent -> deleteTag()); setEventHandler(actionEvent -> deleteTag());
} }
@ -84,20 +82,20 @@ public class DeleteTagAction extends Action {
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
DrawableTagsManager tagsManager = controller.getTagsManager(); DrawableTagsManager tagsManager = controller.getTagsManager();
// Pull the from the global context to avoid unnecessary calls // Pull the from the global context to avoid unnecessary calls
// to the database. // to the database.
final Collection<AbstractFile> selectedFilesList = final Collection<AbstractFile> selectedFilesList
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next(); AbstractFile file = selectedFilesList.iterator().next();
try { try {
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
tagsManager.deleteContentTag(contentTag); tagsManager.deleteContentTag(contentTag);
} catch (TskCoreException tskCoreException) { } catch (TskCoreException tskCoreException) {
LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS
Platform.runLater(() -> Platform.runLater(()
new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show() -> new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show()
); );
} }
return null; return null;
@ -121,25 +119,25 @@ public class DeleteTagAction extends Action {
TagMenu(ImageGalleryController controller) { TagMenu(ImageGalleryController controller) {
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon())); setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon()));
setText(Bundle.DeleteDrawableTagAction_displayName()); setText(Bundle.DeleteDrawableTagAction_displayName());
// For this menu, we shouldn't have more than one file selected. // For this menu, we shouldn't have more than one file selected.
// Therefore, we will simply grab the first file and work with that. // Therefore, we will simply grab the first file and work with that.
final Collection<AbstractFile> selectedFilesList = final Collection<AbstractFile> selectedFilesList
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class)); = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
AbstractFile file = selectedFilesList.iterator().next(); AbstractFile file = selectedFilesList.iterator().next();
try {
List<ContentTag> existingTagsList =
Case.getCurrentCase().getServices().getTagsManager()
.getContentTagsByContent(file);
Collection<TagName> tagNamesList = try {
controller.getTagsManager().getNonCategoryTagNames(); List<ContentTag> existingTagsList
= Case.getCurrentCase().getServices().getTagsManager()
.getContentTagsByContent(file);
Collection<TagName> tagNamesList
= controller.getTagsManager().getNonCategoryTagNames();
Iterator<TagName> tagNameIterator = tagNamesList.iterator(); Iterator<TagName> tagNameIterator = tagNamesList.iterator();
for(int i=0; tagNameIterator.hasNext(); i++) { for (int i = 0; tagNameIterator.hasNext(); i++) {
TagName tagName = tagNameIterator.next(); TagName tagName = tagNameIterator.next();
for(ContentTag contentTag : existingTagsList) { for (ContentTag contentTag : existingTagsList) {
if(contentTag.getName().getId() == tagName.getId()) { if (contentTag.getName().getId() == tagName.getId()) {
DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId()); DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId());
MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction); MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction);
getItems().add(tagNameItem); getItems().add(tagNameItem);
@ -151,7 +149,7 @@ public class DeleteTagAction extends Action {
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS .log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
} }
if(getItems().isEmpty()) { if (getItems().isEmpty()) {
setDisable(true); setDisable(true);
} }
} }