mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-17 02:07:42 +00:00
Merge remote-tracking branch 'upstream/develop' into 3173_DisplayDataSourceSizeMetrics
This commit is contained in:
commit
a49d532ee6
@ -16,6 +16,7 @@
|
||||
<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-parsers" rev="1.14"/>
|
||||
<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"/>
|
||||
|
||||
|
@ -1,10 +1,13 @@
|
||||
file.reference.activemq-all-5.11.1.jar=release/modules/ext/activemq-all-5.11.1.jar
|
||||
file.reference.c3p0-0.9.5.jar=release/modules/ext/c3p0-0.9.5.jar
|
||||
file.reference.commons-compress-1.12.jar=release/modules/ext/commons-compress-1.12.jar
|
||||
file.reference.commons-dbcp2-2.1.1.jar=release\\modules\\ext\\commons-dbcp2-2.1.1.jar
|
||||
file.reference.commons-pool2-2.4.2.jar=release\\modules\\ext\\commons-pool2-2.4.2.jar
|
||||
file.reference.jdom-2.0.5-contrib.jar=release/modules/ext/jdom-2.0.5-contrib.jar
|
||||
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.mchange-commons-java-0.2.9.jar=release/modules/ext/mchange-commons-java-0.2.9.jar
|
||||
file.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1.jar
|
||||
file.reference.metadata-extractor-2.9.1.jar=release/modules/ext/metadata-extractor-2.9.1.jar
|
||||
file.reference.postgresql-9.4.1211.jre7.jar=release/modules/ext/postgresql-9.4.1211.jre7.jar
|
||||
file.reference.opencv-248.jar=release/modules/ext/opencv-248.jar
|
||||
file.reference.Rejistry-1.0-SNAPSHOT.jar=release/modules/ext/Rejistry-1.0-SNAPSHOT.jar
|
||||
@ -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.StixLib.jar=release/modules/ext/StixLib.jar
|
||||
file.reference.tika-core-1.14.jar=release/modules/ext/tika-core-1.14.jar
|
||||
file.reference.tika-parsers-1.14.jar=release/modules/ext/tika-parsers-1.14.jar
|
||||
file.reference.Tsk_DataModel_PostgreSQL.jar=release/modules/ext/Tsk_DataModel_PostgreSQL.jar
|
||||
file.reference.xmpcore-5.1.2.jar=release/modules/ext/xmpcore-5.1.2.jar
|
||||
file.reference.curator-client-2.8.0.jar=release/modules/ext/curator-client-2.8.0.jar
|
||||
@ -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
|
||||
javac.source=1.8
|
||||
javac.compilerargs=-Xlint -Xlint:-serial
|
||||
javadoc.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip
|
||||
license.file=../LICENSE-2.0.txt
|
||||
nbm.homepage=http://www.sleuthkit.org/
|
||||
nbm.module.author=Brian Carrier
|
||||
nbm.needs.restart=true
|
||||
source.reference.metadata-extractor-2.8.1.jar=release/modules/ext/metadata-extractor-2.8.1-src.zip!/Source/
|
||||
source.reference.curator-recipes-2.8.0.jar=release/modules/ext/curator-recipes-2.8.0-sources.jar
|
||||
spec.version.base=10.9
|
||||
|
||||
|
@ -307,7 +307,6 @@
|
||||
<package>org.sleuthkit.autopsy.datasourceprocessors</package>
|
||||
<package>org.sleuthkit.autopsy.directorytree</package>
|
||||
<package>org.sleuthkit.autopsy.events</package>
|
||||
<package>org.sleuthkit.autopsy.externalresults</package>
|
||||
<package>org.sleuthkit.autopsy.filesearch</package>
|
||||
<package>org.sleuthkit.autopsy.guiutils</package>
|
||||
<package>org.sleuthkit.autopsy.ingest</package>
|
||||
@ -321,93 +320,25 @@
|
||||
<package>org.sleuthkit.autopsy.report</package>
|
||||
<package>org.sleuthkit.datamodel</package>
|
||||
</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>
|
||||
<runtime-relative-path>ext/jdom-2.0.5.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/jdom-2.0.5.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/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>
|
||||
<runtime-relative-path>ext/tika-core-1.14.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/tika-core-1.14.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/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>
|
||||
<runtime-relative-path>ext/Tsk_DataModel_PostgreSQL.jar</runtime-relative-path>
|
||||
<binary-origin>release/modules/ext/Tsk_DataModel_PostgreSQL.jar</binary-origin>
|
||||
</class-path-extension>
|
||||
<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>
|
||||
<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>
|
||||
<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/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>
|
||||
<binary-origin>release\modules\ext\commons-dbcp2-2.1.1.jar</binary-origin>
|
||||
</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>
|
||||
<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>
|
||||
</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>
|
||||
</configuration>
|
||||
</project>
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -26,12 +26,14 @@ import javax.swing.AbstractAction;
|
||||
import javax.swing.JMenu;
|
||||
import javax.swing.JMenuItem;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.actions.Presenter;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* An abstract base class for Actions that allow users to tag SleuthKit data
|
||||
@ -107,7 +109,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
|
||||
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
|
||||
String tagDisplayName = entry.getKey();
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
|
||||
String notableString = entry.getValue().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
|
||||
// for the bookmark tag name only, added shortcut label
|
||||
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
|
||||
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT);
|
||||
@ -122,7 +125,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
JMenuItem empty = new JMenuItem(NbBundle.getMessage(this.getClass(), "AddTagAction.noTags"));
|
||||
empty.setEnabled(false);
|
||||
quickTagMenu.add(empty);
|
||||
}
|
||||
}
|
||||
|
||||
quickTagMenu.addSeparator();
|
||||
|
||||
@ -155,10 +158,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
/**
|
||||
* Method to add to the action listener for each menu item. Allows a tag
|
||||
* display name to be added to the menu with an action listener without
|
||||
* having to instantiate a TagName object for it.
|
||||
* When the method is called, the TagName object is created here if it
|
||||
* doesn't already exist.
|
||||
*
|
||||
* having to instantiate a TagName object for it. When the method is
|
||||
* called, the TagName object is created here if it doesn't already
|
||||
* exist.
|
||||
*
|
||||
* @param tagDisplayName display name for the tag name
|
||||
* @param tagName TagName object associated with the tag name,
|
||||
* may be null
|
||||
|
@ -4,7 +4,7 @@ GetTagNameDialog.okButton.text=OK
|
||||
GetTagNameDialog.preexistingLabel.text=Pre-existing Tag Names:
|
||||
GetTagNameDialog.newTagPanel.border.title=New Tag
|
||||
GetTagNameDialog.tagNameLabel.text=Tag Name:
|
||||
GetTagNameAndCommentDialog.newTagButton.text=New Tag Name
|
||||
GetTagNameAndCommentDialog.newTagButton.text=New Tag
|
||||
GetTagNameAndCommentDialog.okButton.text=OK
|
||||
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
|
||||
GetTagNameAndCommentDialog.commentText.text=
|
||||
@ -12,7 +12,6 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment:
|
||||
# To change this template, choose Tools | Templates
|
||||
# and open the template in the editor.
|
||||
GetTagNameAndCommentDialog.cancelButton.text=Cancel
|
||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||
GetTagNameAndCommentDialog.tagLabel.text=Tag:
|
||||
AddTagAction.bookmarkFile=Bookmark file
|
||||
AddTagAction.quickTag=Quick Tag
|
||||
@ -45,3 +44,4 @@ ShowIngestProgressSnapshotAction.actionName.text=Get Ingest Progress Snapshot
|
||||
OpenPythonModulesFolderAction.actionName.text=Python Plugins
|
||||
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python plugins folder not found: {0}
|
||||
CTL_OpenPythonModulesFolderAction=Python Plugins
|
||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||
|
@ -8,7 +8,6 @@ GetTagNameAndCommentDialog.okButton.text=OK
|
||||
GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044
|
||||
GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a
|
||||
GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e
|
||||
GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a
|
||||
AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||
AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||
@ -48,4 +47,5 @@ CTL_OpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c
|
||||
OpenOutputFolder.error1=\u6b21\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
|
||||
OpenOutputFolder.noCaseOpen=\u30aa\u30fc\u30d7\u30f3\u30b1\u30fc\u30b9\u304c\u306a\u3044\u306e\u3067\u3001\u4f5c\u696d\u4e2d\u306e\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u3042\u308a\u307e\u305b\u3093\u3002
|
||||
GetTagNameDialog.illegalChars.msg=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57\u304c\u542b\u307e\u308c\u3066\u3044\u307e\u3059\u3002\n\u6b21\u306e\u6587\u5b57\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\uff1a\\ \: * ? " < > |
|
||||
OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
|
||||
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
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -43,6 +43,7 @@ import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to blackboard
|
||||
@ -52,7 +53,7 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
"DeleteFileBlackboardArtifactTagAction.deleteTag=Remove Result Tag"
|
||||
})
|
||||
public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implements Presenter.Popup {
|
||||
|
||||
|
||||
private static final Logger LOGGER = Logger.getLogger(DeleteFileBlackboardArtifactTagAction.class.getName());
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -89,27 +90,27 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"# {0} - artifactID",
|
||||
"DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."})
|
||||
"DeleteFileBlackboardArtifactTagAction.deleteTag.alert=Unable to untag artifact {0}."})
|
||||
protected void deleteTag(TagName tagName, BlackboardArtifactTag artifactTag, long artifactId) {
|
||||
new SwingWorker<Void, Void>() {
|
||||
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
|
||||
|
||||
// Pull the from the global context to avoid unnecessary calls
|
||||
// to the database.
|
||||
final Collection<AbstractFile> selectedFilesList =
|
||||
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
final Collection<AbstractFile> selectedFilesList
|
||||
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
AbstractFile file = selectedFilesList.iterator().next();
|
||||
|
||||
|
||||
try {
|
||||
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
|
||||
tagsManager.deleteBlackboardArtifactTag(artifactTag);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
LOGGER.log(Level.SEVERE, "Error untagging artifact", tskCoreException); //NON-NLS
|
||||
Platform.runLater(() ->
|
||||
new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show()
|
||||
Platform.runLater(()
|
||||
-> new Alert(Alert.AlertType.ERROR, Bundle.DeleteFileBlackboardArtifactTagAction_deleteTag_alert(artifactId)).show()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@ -133,21 +134,21 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
|
||||
* comment.
|
||||
*/
|
||||
@NbBundle.Messages({"# {0} - artifactID",
|
||||
"DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."})
|
||||
"DeleteFileBlackboardArtifactTagAction.deleteTags.alert=Unable to untag artifact {0}."})
|
||||
private class TagMenu extends JMenu {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
TagMenu() {
|
||||
super(getActionDisplayName());
|
||||
|
||||
final Collection<BlackboardArtifact> selectedBlackboardArtifactsList =
|
||||
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||
|
||||
if(!selectedBlackboardArtifactsList.isEmpty()) {
|
||||
BlackboardArtifact artifact =
|
||||
selectedBlackboardArtifactsList.iterator().next();
|
||||
|
||||
|
||||
final Collection<BlackboardArtifact> selectedBlackboardArtifactsList
|
||||
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||
|
||||
if (!selectedBlackboardArtifactsList.isEmpty()) {
|
||||
BlackboardArtifact artifact
|
||||
= selectedBlackboardArtifactsList.iterator().next();
|
||||
|
||||
// Get the current set of tag names.
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
|
||||
@ -163,17 +164,18 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
|
||||
// a tag with the associated tag name.
|
||||
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
|
||||
try {
|
||||
List<BlackboardArtifactTag> existingTagsList =
|
||||
Case.getCurrentCase().getServices().getTagsManager()
|
||||
.getBlackboardArtifactTagsByArtifact(artifact);
|
||||
List<BlackboardArtifactTag> existingTagsList
|
||||
= Case.getCurrentCase().getServices().getTagsManager()
|
||||
.getBlackboardArtifactTagsByArtifact(artifact);
|
||||
|
||||
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
|
||||
String tagDisplayName = entry.getKey();
|
||||
|
||||
TagName tagName = entry.getValue();
|
||||
for(BlackboardArtifactTag artifactTag : existingTagsList) {
|
||||
if(tagDisplayName.equals(artifactTag.getName().getDisplayName())) {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
|
||||
for (BlackboardArtifactTag artifactTag : existingTagsList) {
|
||||
if (tagDisplayName.equals(artifactTag.getName().getDisplayName())) {
|
||||
String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
|
||||
tagNameItem.addActionListener((ActionEvent e) -> {
|
||||
deleteTag(tagName, artifactTag, artifact.getArtifactID());
|
||||
});
|
||||
@ -187,7 +189,7 @@ public class DeleteFileBlackboardArtifactTagAction extends AbstractAction implem
|
||||
}
|
||||
}
|
||||
|
||||
if(getItemCount() == 0) {
|
||||
if (getItemCount() == 0) {
|
||||
setEnabled(false);
|
||||
}
|
||||
}
|
||||
|
@ -42,6 +42,7 @@ import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to content.
|
||||
@ -169,7 +170,8 @@ public class DeleteFileContentTagAction extends AbstractAction implements Presen
|
||||
TagName tagName = entry.getValue();
|
||||
for(ContentTag contentTag : existingTagsList) {
|
||||
if(tagDisplayName.equals(contentTag.getName().getDisplayName())) {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
|
||||
String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
JMenuItem tagNameItem = new JMenuItem(tagDisplayName + notableString);
|
||||
tagNameItem.addActionListener((ActionEvent e) -> {
|
||||
deleteTag(tagName, contentTag, file.getId());
|
||||
});
|
||||
|
@ -28,7 +28,7 @@
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" 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"/>
|
||||
<EmptySpace 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"/>
|
||||
</Group>
|
||||
<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="tagCombo" pref="214" max="32767" attributes="0"/>
|
||||
<Component id="tagCombo" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
@ -108,8 +107,8 @@
|
||||
</Property>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<String>()"/>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<String>"/>
|
||||
<AuxValue name="JavaCodeGenerator_CreateCodeCustom" type="java.lang.String" value="new javax.swing.JComboBox<TagName>()"/>
|
||||
<AuxValue name="JavaCodeGenerator_TypeParameters" type="java.lang.String" value="<TagName>"/>
|
||||
</AuxValues>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="tagLabel">
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2016 Basis Technology Corp.
|
||||
*
|
||||
* 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.
|
||||
@ -18,17 +18,20 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.Component;
|
||||
import java.awt.Window;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
import java.util.logging.Level;
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.ActionMap;
|
||||
import javax.swing.DefaultListCellRenderer;
|
||||
import javax.swing.InputMap;
|
||||
import javax.swing.JComponent;
|
||||
import javax.swing.JDialog;
|
||||
import javax.swing.JList;
|
||||
import javax.swing.KeyStroke;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
@ -37,15 +40,14 @@ import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
public class GetTagNameAndCommentDialog extends JDialog {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
private static final String NO_TAG_NAMES_MESSAGE = NbBundle.getMessage(GetTagNameAndCommentDialog.class,
|
||||
"GetTagNameAndCommentDialog.noTags");
|
||||
private final Map<String, TagName> tagNamesMap = new TreeMap<>();
|
||||
private final Set<TagName> tagNamesSet = new HashSet<>();
|
||||
private TagNameAndComment tagNameAndComment = null;
|
||||
|
||||
|
||||
public static class TagNameAndComment {
|
||||
|
||||
private final TagName tagName;
|
||||
@ -68,7 +70,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
/**
|
||||
* Show the Tag Name and Comment Dialog and return the TagNameAndContent
|
||||
* chosen by the user. The dialog will be centered with the main autopsy
|
||||
* window as its owner.
|
||||
* window as its owner.
|
||||
*
|
||||
* @return a TagNameAndComment instance containing the TagName selected by
|
||||
* the user and the entered comment, or null if the user canceled
|
||||
@ -102,21 +104,34 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
ModalityType.APPLICATION_MODAL);
|
||||
}
|
||||
|
||||
|
||||
private void display() {
|
||||
initComponents();
|
||||
|
||||
tagCombo.setRenderer(new DefaultListCellRenderer() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
@Override
|
||||
public Component getListCellRendererComponent(JList<?> list, Object value, int index, boolean isSelected, boolean cellHasFocus) {
|
||||
String status = ((TagName) value).getKnownStatus() == TskData.FileKnown.BAD ?TagsManager.getNotableTagLabel() : "";
|
||||
String newValue = ((TagName) value).getDisplayName() + status;
|
||||
return super.getListCellRendererComponent(list, newValue, index, isSelected, cellHasFocus);
|
||||
}
|
||||
});
|
||||
// Set up the dialog to close when Esc is pressed.
|
||||
String cancelName = NbBundle.getMessage(this.getClass(), "GetTagNameAndCommentDialog.cancelName");
|
||||
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
|
||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||
ActionMap actionMap = getRootPane().getActionMap();
|
||||
|
||||
actionMap.put(cancelName, new AbstractAction() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
dispose();
|
||||
}
|
||||
});
|
||||
}
|
||||
);
|
||||
|
||||
// Populate the combo box with the available tag names and save the
|
||||
// tag name DTOs to be enable to return the one the user selects.
|
||||
@ -124,23 +139,22 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
// not exist in the database).
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
try {
|
||||
tagNamesMap.putAll(tagsManager.getDisplayNamesToTagNamesMap());
|
||||
tagNamesSet.addAll(tagsManager.getAllTagNames());
|
||||
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||
Logger.getLogger(GetTagNameAndCommentDialog.class
|
||||
.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||
}
|
||||
if (null != tagNamesMap && tagNamesMap.isEmpty()) {
|
||||
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
|
||||
} else {
|
||||
for (String tagDisplayName : tagNamesMap.keySet()) {
|
||||
tagCombo.addItem(tagDisplayName);
|
||||
}
|
||||
for (TagName tag : tagNamesSet) {
|
||||
|
||||
tagCombo.addItem(tag);
|
||||
}
|
||||
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(this.getOwner());
|
||||
setVisible(true);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This method is called from within the constructor to initialize the form.
|
||||
* WARNING: Do NOT modify this code. The content of this method is always
|
||||
@ -152,7 +166,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
|
||||
okButton = new javax.swing.JButton();
|
||||
cancelButton = new javax.swing.JButton();
|
||||
tagCombo = new javax.swing.JComboBox<String>();
|
||||
tagCombo = new javax.swing.JComboBox<TagName>();
|
||||
tagLabel = new javax.swing.JLabel();
|
||||
commentLabel = new javax.swing.JLabel();
|
||||
commentText = new javax.swing.JTextField();
|
||||
@ -203,7 +217,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(newTagButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 48, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, 165, Short.MAX_VALUE)
|
||||
.addComponent(okButton, javax.swing.GroupLayout.PREFERRED_SIZE, 67, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cancelButton))
|
||||
@ -212,10 +226,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
.addComponent(commentLabel)
|
||||
.addComponent(tagLabel))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING, false)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(commentText)
|
||||
.addComponent(tagCombo, 0, 214, Short.MAX_VALUE))
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addComponent(tagCombo, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
@ -246,21 +259,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
String tagDisplayName = (String) tagCombo.getSelectedItem();
|
||||
TagName tagNameFromCombo = tagNamesMap.get(tagDisplayName);
|
||||
if (tagNameFromCombo == null) {
|
||||
try {
|
||||
tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
|
||||
} catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||
try {
|
||||
tagNameFromCombo = Case.getCurrentCase().getServices().getTagsManager().getDisplayNamesToTagNamesMap().get(tagDisplayName);
|
||||
} catch (TskCoreException ex1) {
|
||||
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, tagDisplayName + " already exists in database but an error occurred in retrieving it.", ex1); //NON-NLS
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
TagName tagNameFromCombo = (TagName) tagCombo.getSelectedItem();
|
||||
tagNameAndComment = new TagNameAndComment(tagNameFromCombo, commentText.getText());
|
||||
dispose();
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
@ -278,9 +277,9 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||
TagName newTagName = GetTagNameDialog.doDialog(this);
|
||||
if (newTagName != null) {
|
||||
tagNamesMap.put(newTagName.getDisplayName(), newTagName);
|
||||
tagCombo.addItem(newTagName.getDisplayName());
|
||||
tagCombo.setSelectedItem(newTagName.getDisplayName());
|
||||
tagNamesSet.add(newTagName);
|
||||
tagCombo.addItem(newTagName);
|
||||
tagCombo.setSelectedItem(newTagName);
|
||||
}
|
||||
}//GEN-LAST:event_newTagButtonActionPerformed
|
||||
|
||||
@ -290,7 +289,7 @@ public class GetTagNameAndCommentDialog extends JDialog {
|
||||
private javax.swing.JTextField commentText;
|
||||
private javax.swing.JButton newTagButton;
|
||||
private javax.swing.JButton okButton;
|
||||
private javax.swing.JComboBox<String> tagCombo;
|
||||
private javax.swing.JComboBox<TagName> tagCombo;
|
||||
private javax.swing.JLabel tagLabel;
|
||||
// End of variables declaration//GEN-END:variables
|
||||
}
|
||||
|
@ -142,11 +142,20 @@
|
||||
<Layout>
|
||||
<DimensionLayout dim="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"/>
|
||||
<Component id="tagNameLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace min="-2" pref="36" max="-2" attributes="0"/>
|
||||
<Component id="tagNameField" pref="235" max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="descriptionScrollPane" alignment="1" 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"/>
|
||||
</Group>
|
||||
</Group>
|
||||
@ -154,12 +163,17 @@
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" 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"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="tagNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="tagNameField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace pref="164" max="32767" attributes="0"/>
|
||||
<Component id="tagNameField" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="descriptionLabel" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" 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>
|
||||
</DimensionLayout>
|
||||
@ -182,6 +196,38 @@
|
||||
<EventHandler event="keyReleased" listener="java.awt.event.KeyListener" parameters="java.awt.event.KeyEvent" handler="tagNameFieldKeyReleased"/>
|
||||
</Events>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Container>
|
||||
</SubComponents>
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
*
|
||||
* Copyright 2011-2016 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.
|
||||
@ -36,13 +36,17 @@ import javax.swing.KeyStroke;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
import org.openide.util.ImageUtilities;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@Messages({"GetTagNameDialog.descriptionLabel.text=Description:",
|
||||
"GetTagNameDialog.notableCheckbox.text=Tag indicates item is notable."})
|
||||
public class GetTagNameDialog extends JDialog {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -79,7 +83,7 @@ public class GetTagNameDialog extends JDialog {
|
||||
}
|
||||
|
||||
private GetTagNameDialog(Window owner) {
|
||||
super(owner,
|
||||
super(owner,
|
||||
NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.createTag"),
|
||||
ModalityType.APPLICATION_MODAL);
|
||||
}
|
||||
@ -95,7 +99,7 @@ public class GetTagNameDialog extends JDialog {
|
||||
ActionMap actionMap = getRootPane().getActionMap();
|
||||
actionMap.put(cancelName, new AbstractAction() {
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
cancelButtonActionPerformed(e);
|
||||
@ -120,9 +124,9 @@ public class GetTagNameDialog extends JDialog {
|
||||
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(this.getOwner());
|
||||
setVisible(true);
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
|
||||
private class TagsTableModel extends AbstractTableModel {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -172,6 +176,10 @@ public class GetTagNameDialog extends JDialog {
|
||||
newTagPanel = new javax.swing.JPanel();
|
||||
tagNameLabel = new javax.swing.JLabel();
|
||||
tagNameField = new javax.swing.JTextField();
|
||||
descriptionLabel = new javax.swing.JLabel();
|
||||
descriptionScrollPane = new javax.swing.JScrollPane();
|
||||
descriptionTextArea = new javax.swing.JTextArea();
|
||||
notableCheckbox = new javax.swing.JCheckBox();
|
||||
|
||||
setDefaultCloseOperation(javax.swing.WindowConstants.DISPOSE_ON_CLOSE);
|
||||
addKeyListener(new java.awt.event.KeyAdapter() {
|
||||
@ -223,25 +231,46 @@ public class GetTagNameDialog extends JDialog {
|
||||
}
|
||||
});
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.descriptionLabel.text")); // NOI18N
|
||||
|
||||
descriptionTextArea.setColumns(20);
|
||||
descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
|
||||
descriptionTextArea.setRows(3);
|
||||
descriptionScrollPane.setViewportView(descriptionTextArea);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(notableCheckbox, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.notableCheckbox.text")); // NOI18N
|
||||
|
||||
javax.swing.GroupLayout newTagPanelLayout = new javax.swing.GroupLayout(newTagPanel);
|
||||
newTagPanel.setLayout(newTagPanelLayout);
|
||||
newTagPanelLayout.setHorizontalGroup(
|
||||
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(newTagPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addComponent(tagNameLabel)
|
||||
.addGap(36, 36, 36)
|
||||
.addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 235, Short.MAX_VALUE)
|
||||
.addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(descriptionScrollPane, javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(tagNameField, javax.swing.GroupLayout.DEFAULT_SIZE, 323, Short.MAX_VALUE)
|
||||
.addGroup(newTagPanelLayout.createSequentialGroup()
|
||||
.addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(notableCheckbox)
|
||||
.addComponent(descriptionLabel)
|
||||
.addComponent(tagNameLabel))
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
);
|
||||
newTagPanelLayout.setVerticalGroup(
|
||||
newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(newTagPanelLayout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(newTagPanelLayout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(tagNameLabel)
|
||||
.addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addContainerGap(164, Short.MAX_VALUE))
|
||||
.addGap(6, 6, 6)
|
||||
.addComponent(tagNameLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(tagNameField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(descriptionLabel)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(descriptionScrollPane, javax.swing.GroupLayout.PREFERRED_SIZE, 57, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(notableCheckbox)
|
||||
.addContainerGap(31, Short.MAX_VALUE))
|
||||
);
|
||||
|
||||
javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
|
||||
@ -288,8 +317,14 @@ public class GetTagNameDialog extends JDialog {
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
@NbBundle.Messages({"GetTagNameDialog.tagNameAlreadyExists.message=Tag name must be unique. A tag with this name already exists.",
|
||||
"GetTagNameDialog.tagNameAlreadyExists.title=Duplicate Tag Name",
|
||||
"GetTagNameDialog.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)",
|
||||
"GetTagNameDialog.tagDescriptionIllegalCharacters.title=Invalid character in tag description"})
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
String tagDisplayName = tagNameField.getText();
|
||||
String userTagDescription = descriptionTextArea.getText();
|
||||
TskData.FileKnown status = notableCheckbox.isSelected() ? TskData.FileKnown.BAD : TskData.FileKnown.UNKNOWN;
|
||||
if (tagDisplayName.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(),
|
||||
@ -301,11 +336,18 @@ public class GetTagNameDialog extends JDialog {
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalChars.msg"),
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.illegalCharsErr"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} else if (userTagDescription.contains(",")
|
||||
|| userTagDescription.contains(";")) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.message"),
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagDescriptionIllegalCharacters.title"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
} else {
|
||||
tagName = tagNamesMap.get(tagDisplayName);
|
||||
|
||||
if (tagName == null) {
|
||||
try {
|
||||
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
|
||||
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName, userTagDescription, TagName.HTML_COLOR.NONE, status);
|
||||
dispose();
|
||||
} catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex); //NON-NLS
|
||||
@ -331,7 +373,10 @@ public class GetTagNameDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
dispose();
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.message"),
|
||||
NbBundle.getMessage(this.getClass(), "GetTagNameDialog.tagNameAlreadyExists.title"),
|
||||
JOptionPane.INFORMATION_MESSAGE);
|
||||
}
|
||||
}
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
@ -350,8 +395,12 @@ public class GetTagNameDialog extends JDialog {
|
||||
|
||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||
private javax.swing.JButton cancelButton;
|
||||
private javax.swing.JLabel descriptionLabel;
|
||||
private javax.swing.JScrollPane descriptionScrollPane;
|
||||
private javax.swing.JTextArea descriptionTextArea;
|
||||
private javax.swing.JScrollPane jScrollPane1;
|
||||
private javax.swing.JPanel newTagPanel;
|
||||
private javax.swing.JCheckBox notableCheckbox;
|
||||
private javax.swing.JButton okButton;
|
||||
private javax.swing.JLabel preexistingLabel;
|
||||
private javax.swing.JTextField tagNameField;
|
||||
|
@ -9,9 +9,7 @@ TagNameDialog.JOptionPane.tagNameEmpty.title=Empty tag name
|
||||
TagOptionsPanel.tagTypesListLabel.text=Tag Names:
|
||||
TagOptionsPanel.deleteTagNameButton.text=Delete Tag
|
||||
TagOptionsPanel.newTagNameButton.text=New Tag
|
||||
TagNameDialog.descriptionLabel.text=Description:
|
||||
TagNameDialog.okButton.text=OK
|
||||
TagNameDialog.cancelButton.text=Cancel
|
||||
TagNameDialog.tagNameTextField.text=
|
||||
TagNameDialog.newTagNameLabel.text=Name:
|
||||
TagNameDialog.notableCheckbox.text=Tag indicates item is notable.
|
@ -107,8 +107,7 @@ final class TagNameDefinition implements Comparable<TagNameDefinition> {
|
||||
}
|
||||
|
||||
/**
|
||||
* The status which items which have this tag applied to them should have in
|
||||
* the central repository.
|
||||
* The status which will be applied to items with this tag.
|
||||
*
|
||||
* @return a value of TskData.FileKnown which is associated with this tag
|
||||
*/
|
||||
|
@ -117,7 +117,7 @@
|
||||
<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="5"/>
|
||||
<Property name="rows" type="int" value="3"/>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
|
@ -1,20 +1,20 @@
|
||||
/*
|
||||
* 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.
|
||||
* 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.casemodule.services;
|
||||
|
||||
@ -31,6 +31,8 @@ import org.openide.util.NbBundle;
|
||||
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 {
|
||||
|
||||
private static final long serialVersionUID = 1L;
|
||||
@ -60,7 +62,7 @@ final class TagNameDialog extends javax.swing.JDialog {
|
||||
initComponents();
|
||||
tagNameTextField.setText(tagNameToEdit.getDisplayName());
|
||||
descriptionTextArea.setText(tagNameToEdit.getDescription());
|
||||
notableCheckbox.setSelected(tagNameToEdit.getKnownStatus()== TskData.FileKnown.BAD);
|
||||
notableCheckbox.setSelected(tagNameToEdit.getKnownStatus() == TskData.FileKnown.BAD);
|
||||
tagNameTextField.setEnabled(false);
|
||||
this.display();
|
||||
}
|
||||
@ -127,24 +129,35 @@ final class TagNameDialog extends javax.swing.JDialog {
|
||||
*
|
||||
* @param okPressed whether the OK button was pressed.
|
||||
*/
|
||||
@Messages({"TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message=Tag descriptions may not contain commas (,) or semicolons (;)",
|
||||
"TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title=Invalid character in tag description"})
|
||||
private void doButtonAction(boolean okPressed) {
|
||||
if (okPressed) {
|
||||
String newTagDisplayName = tagNameTextField.getText().trim();
|
||||
String descriptionText = descriptionTextArea.getText();
|
||||
if (newTagDisplayName.isEmpty()) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.message"),
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameEmpty.title"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//if a tag name contains illegal characters and is not the name of one of the standard tags
|
||||
if (TagsManager.containsIllegalCharacters(newTagDisplayName) && !TagNameDefinition.getStandardTagNames().contains(newTagDisplayName)) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.message"),
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagNameIllegalCharacters.title"),
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"),
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
} else if (descriptionText.contains(",")
|
||||
|| descriptionText.contains(";")) {
|
||||
JOptionPane.showMessageDialog(null,
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.message"),
|
||||
NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.JOptionPane.tagDescriptionIllegalCharacters.title"),
|
||||
JOptionPane.ERROR_MESSAGE);
|
||||
return;
|
||||
}
|
||||
|
||||
userTagDescription = descriptionTextArea.getText();
|
||||
userTagDisplayName = newTagDisplayName;
|
||||
userTagIsNotable = notableCheckbox.isSelected();
|
||||
@ -231,7 +244,7 @@ final class TagNameDialog extends javax.swing.JDialog {
|
||||
|
||||
descriptionTextArea.setColumns(20);
|
||||
descriptionTextArea.setFont(new java.awt.Font("Tahoma", 0, 11)); // NOI18N
|
||||
descriptionTextArea.setRows(5);
|
||||
descriptionTextArea.setRows(3);
|
||||
descriptionScrollPane.setViewportView(descriptionTextArea);
|
||||
|
||||
org.openide.awt.Mnemonics.setLocalizedText(descriptionLabel, org.openide.util.NbBundle.getMessage(TagNameDialog.class, "TagNameDialog.descriptionLabel.text")); // NOI18N
|
||||
|
@ -27,6 +27,7 @@ import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
@ -69,6 +70,15 @@ public class TagsManager implements Closeable {
|
||||
|| tagDisplayName.contains(";"));
|
||||
|
||||
}
|
||||
@NbBundle.Messages({"TagsManager.notableTagEnding.text= (Notable)"})
|
||||
/**
|
||||
* Get String of text which is used to label tags as notable to the user.
|
||||
*
|
||||
* @return Bundle message TagsManager.notableTagEnding.text
|
||||
*/
|
||||
public static String getNotableTagLabel(){
|
||||
return Bundle.TagsManager_notableTagEnding_text();
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the set of display names of the currently available tag types. This
|
||||
|
@ -37,6 +37,7 @@ public class EamDbUtil {
|
||||
private final static Logger LOGGER = Logger.getLogger(EamDbUtil.class.getName());
|
||||
private static final String CENTRAL_REPO_NAME = "CentralRepository";
|
||||
private static final String CENTRAL_REPO_USE_KEY = "db.useCentralRepo";
|
||||
private static final String DEFAULT_ORG_NAME = "Not Specified";
|
||||
|
||||
/**
|
||||
* Close the prepared statement.
|
||||
@ -175,11 +176,51 @@ public class EamDbUtil {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check whether the given org is the default organization.
|
||||
*
|
||||
* @param org
|
||||
* @return true if it is the default org, false otherwise
|
||||
*/
|
||||
public static boolean isDefaultOrg(EamOrganization org) {
|
||||
return DEFAULT_ORG_NAME.equals(org.getName());
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the default organization to the database
|
||||
*
|
||||
* @param conn
|
||||
* @return true if successful, false otherwise
|
||||
*/
|
||||
static boolean insertDefaultOrganization(Connection conn) {
|
||||
if (null == conn) {
|
||||
return false;
|
||||
}
|
||||
|
||||
PreparedStatement preparedStatement = null;
|
||||
String sql = "INSERT INTO organizations(org_name, poc_name, poc_email, poc_phone) VALUES (?, ?, ?, ?)";
|
||||
try {
|
||||
preparedStatement = conn.prepareStatement(sql);
|
||||
preparedStatement.setString(1, DEFAULT_ORG_NAME);
|
||||
preparedStatement.setString(2, "");
|
||||
preparedStatement.setString(3, "");
|
||||
preparedStatement.setString(4, "");
|
||||
preparedStatement.executeUpdate();
|
||||
} catch (SQLException ex) {
|
||||
LOGGER.log(Level.SEVERE, "Error adding default organization", ex);
|
||||
return false;
|
||||
} finally {
|
||||
EamDbUtil.closePreparedStatement(preparedStatement);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the Central Repos use has been enabled.
|
||||
*
|
||||
* @return true if the Central Repo may be configured, false if it should
|
||||
* not be able to be
|
||||
* not be able to be
|
||||
*/
|
||||
public static boolean useCentralRepo() {
|
||||
return Boolean.parseBoolean(ModuleSettings.getConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY));
|
||||
@ -190,7 +231,7 @@ public class EamDbUtil {
|
||||
* configured.
|
||||
*
|
||||
* @param centralRepoCheckBoxIsSelected - true if the central repo can be
|
||||
* used
|
||||
* used
|
||||
*/
|
||||
public static void setUseCentralRepo(boolean centralRepoCheckBoxIsSelected) {
|
||||
ModuleSettings.setConfigSetting(CENTRAL_REPO_NAME, CENTRAL_REPO_USE_KEY, Boolean.toString(centralRepoCheckBoxIsSelected));
|
||||
|
@ -485,7 +485,8 @@ public final class PostgresEamDbSettings {
|
||||
}
|
||||
|
||||
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
|
||||
&& EamDbUtil.insertSchemaVersion(conn);
|
||||
&& EamDbUtil.insertSchemaVersion(conn)
|
||||
&& EamDbUtil.insertDefaultOrganization(conn);
|
||||
EamDbUtil.closeConnection(conn);
|
||||
|
||||
return result;
|
||||
|
@ -434,7 +434,8 @@ public final class SqliteEamDbSettings {
|
||||
}
|
||||
|
||||
boolean result = EamDbUtil.insertDefaultCorrelationTypes(conn)
|
||||
&& EamDbUtil.insertSchemaVersion(conn);
|
||||
&& EamDbUtil.insertSchemaVersion(conn)
|
||||
&& EamDbUtil.insertDefaultOrganization(conn);
|
||||
EamDbUtil.closeConnection(conn);
|
||||
return result;
|
||||
}
|
||||
|
@ -35,6 +35,7 @@ import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
|
||||
@ -72,7 +73,7 @@ public final class ManageOrganizationsDialog extends JDialog {
|
||||
organizationList.setModel(rulesListModel);
|
||||
organizationList.addListSelectionListener(new OrganizationListSelectionListener());
|
||||
populateList();
|
||||
setButtonsEnabled(organizationList.getSelectedValue() != null);
|
||||
setButtonsEnabled(organizationList.getSelectedValue());
|
||||
newOrg = null;
|
||||
} catch (EamDbException ex) {
|
||||
Exceptions.printStackTrace(ex);
|
||||
@ -421,9 +422,15 @@ public final class ManageOrganizationsDialog extends JDialog {
|
||||
return newOrg;
|
||||
}
|
||||
|
||||
private void setButtonsEnabled(boolean isSelected) {
|
||||
editButton.setEnabled(isSelected);
|
||||
deleteButton.setEnabled(isSelected);
|
||||
private void setButtonsEnabled(EamOrganization selectedOrg) {
|
||||
boolean isSelected = (selectedOrg != null);
|
||||
boolean isDefaultOrg = false;
|
||||
if(selectedOrg != null){
|
||||
isDefaultOrg = EamDbUtil.isDefaultOrg(selectedOrg);
|
||||
}
|
||||
|
||||
editButton.setEnabled(isSelected && (! isDefaultOrg));
|
||||
deleteButton.setEnabled(isSelected && (! isDefaultOrg));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -436,9 +443,8 @@ public final class ManageOrganizationsDialog extends JDialog {
|
||||
if (e.getValueIsAdjusting()) {
|
||||
return;
|
||||
}
|
||||
EamOrganization selected = organizationList.getSelectedValue();
|
||||
boolean isSelected = (selected != null);
|
||||
setButtonsEnabled(isSelected);
|
||||
EamOrganization selected = organizationList.getSelectedValue();
|
||||
setButtonsEnabled(selected);
|
||||
if (selected != null) {
|
||||
orgNameTextField.setText(selected.getName());
|
||||
pocNameTextField.setText(selected.getPocName());
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-2017 Basis Technology Corp.
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -44,7 +44,7 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
|
||||
static final String[] SUPPORTED_EXTENSIONS = {"zip", "rar", "arj", "7z", "7zip", "gzip", "gz", "bzip2", "tar", "tgz",}; // "iso"}; NON-NLS
|
||||
private String moduleDirRelative;
|
||||
private String moduleDirAbsolute;
|
||||
private ImageExtractor imageExtractor;
|
||||
private MSOfficeEmbeddedContentExtractor officeExtractor;
|
||||
private SevenZipExtractor archiveExtractor;
|
||||
private FileTypeDetector fileTypeDetector;
|
||||
|
||||
@ -98,10 +98,10 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
|
||||
}
|
||||
|
||||
/*
|
||||
* Construct an embedded images extractor for processing Microsoft
|
||||
* Construct an embedded content extractor for processing Microsoft
|
||||
* Office documents.
|
||||
*/
|
||||
this.imageExtractor = new ImageExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute);
|
||||
this.officeExtractor = new MSOfficeEmbeddedContentExtractor(context, fileTypeDetector, moduleDirRelative, moduleDirAbsolute);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -134,8 +134,8 @@ public final class EmbeddedFileExtractorIngestModule extends FileIngestModuleAda
|
||||
*/
|
||||
if (archiveExtractor.isSevenZipExtractionSupported(abstractFile)) {
|
||||
archiveExtractor.unpack(abstractFile);
|
||||
} else if (imageExtractor.isImageExtractionSupported(abstractFile)) {
|
||||
imageExtractor.extractImage(abstractFile);
|
||||
} else if (officeExtractor.isContentExtractionSupported(abstractFile)) {
|
||||
officeExtractor.extractEmbeddedContent(abstractFile);
|
||||
}
|
||||
return ProcessResult.OK;
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011-2017 Basis Technology Corp.
|
||||
* Copyright 2015 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -21,14 +21,16 @@ package org.sleuthkit.autopsy.modules.embeddedfileextractor;
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.lang.IllegalArgumentException;
|
||||
import java.lang.IndexOutOfBoundsException;
|
||||
import java.lang.NullPointerException;
|
||||
import java.io.InputStream;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.logging.Level;
|
||||
import org.apache.poi.POIXMLException;
|
||||
import org.apache.commons.io.FileUtils;
|
||||
import org.apache.commons.io.FilenameUtils;
|
||||
import org.apache.commons.io.IOUtils;
|
||||
import org.apache.poi.hwpf.usermodel.Picture;
|
||||
import org.apache.poi.hslf.usermodel.HSLFPictureData;
|
||||
import org.apache.poi.hslf.usermodel.HSLFSlideShow;
|
||||
@ -39,11 +41,18 @@ import org.apache.poi.hwpf.model.PicturesTable;
|
||||
import org.apache.poi.sl.usermodel.PictureData.PictureType;
|
||||
import org.apache.poi.ss.usermodel.Workbook;
|
||||
import org.apache.poi.util.RecordFormatException;
|
||||
import org.apache.poi.xslf.usermodel.XMLSlideShow;
|
||||
import org.apache.poi.xslf.usermodel.XSLFPictureData;
|
||||
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFDocument;
|
||||
import org.apache.poi.xwpf.usermodel.XWPFPictureData;
|
||||
import org.apache.tika.config.TikaConfig;
|
||||
import org.apache.tika.detect.Detector;
|
||||
import org.apache.tika.exception.TikaException;
|
||||
import org.apache.tika.extractor.EmbeddedDocumentExtractor;
|
||||
import org.apache.tika.extractor.ParsingEmbeddedDocumentExtractor;
|
||||
import org.apache.tika.metadata.Metadata;
|
||||
import org.apache.tika.mime.MediaType;
|
||||
import org.apache.tika.mime.MimeTypeException;
|
||||
import org.apache.tika.parser.AutoDetectParser;
|
||||
import org.apache.tika.parser.ParseContext;
|
||||
import org.apache.tika.parser.Parser;
|
||||
import org.apache.tika.sax.BodyContentHandler;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
||||
@ -57,24 +66,34 @@ import org.sleuthkit.datamodel.EncodedFileOutputStream;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.xml.sax.ContentHandler;
|
||||
import org.xml.sax.SAXException;
|
||||
|
||||
class ImageExtractor {
|
||||
/**
|
||||
* Extracts embedded content (e.g. images, audio, video) from Microsoft Office
|
||||
* documents (both original and OOXML forms).
|
||||
*/
|
||||
class MSOfficeEmbeddedContentExtractor {
|
||||
|
||||
private final FileManager fileManager;
|
||||
private final IngestServices services;
|
||||
private static final Logger logger = Logger.getLogger(ImageExtractor.class.getName());
|
||||
private static final Logger LOGGER = Logger.getLogger(MSOfficeEmbeddedContentExtractor.class.getName());
|
||||
private final IngestJobContext context;
|
||||
private String parentFileName;
|
||||
private final String UNKNOWN_NAME_PREFIX = "image_"; //NON-NLS
|
||||
private final String UNKNOWN_IMAGE_NAME_PREFIX = "image_"; //NON-NLS
|
||||
private final FileTypeDetector fileTypeDetector;
|
||||
|
||||
private String moduleDirRelative;
|
||||
private String moduleDirAbsolute;
|
||||
|
||||
private AutoDetectParser parser = new AutoDetectParser();
|
||||
private Detector detector = parser.getDetector();
|
||||
private TikaConfig config = TikaConfig.getDefaultConfig();
|
||||
|
||||
/**
|
||||
* Enum of mimetypes which support image extraction
|
||||
* Enum of mimetypes for which we can extract embedded content.
|
||||
*/
|
||||
enum SupportedImageExtractionFormats {
|
||||
enum SupportedExtractionFormats {
|
||||
|
||||
DOC("application/msword"), //NON-NLS
|
||||
DOCX("application/vnd.openxmlformats-officedocument.wordprocessingml.document"), //NON-NLS
|
||||
@ -85,7 +104,7 @@ class ImageExtractor {
|
||||
|
||||
private final String mimeType;
|
||||
|
||||
SupportedImageExtractionFormats(final String mimeType) {
|
||||
SupportedExtractionFormats(final String mimeType) {
|
||||
this.mimeType = mimeType;
|
||||
}
|
||||
|
||||
@ -93,11 +112,10 @@ class ImageExtractor {
|
||||
public String toString() {
|
||||
return this.mimeType;
|
||||
}
|
||||
// TODO Expand to support more formats
|
||||
}
|
||||
private SupportedImageExtractionFormats abstractFileExtractionFormat;
|
||||
private SupportedExtractionFormats abstractFileExtractionFormat;
|
||||
|
||||
ImageExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) {
|
||||
MSOfficeEmbeddedContentExtractor(IngestJobContext context, FileTypeDetector fileTypeDetector, String moduleDirRelative, String moduleDirAbsolute) {
|
||||
|
||||
this.fileManager = Case.getCurrentCase().getServices().getFileManager();
|
||||
this.services = IngestServices.getInstance();
|
||||
@ -111,15 +129,15 @@ class ImageExtractor {
|
||||
* This method returns true if the file format is currently supported. Else
|
||||
* it returns false. Performs only Apache Tika based detection.
|
||||
*
|
||||
* @param abstractFile The AbstractFilw whose mimetype is to be determined.
|
||||
* @param abstractFile The AbstractFile whose mimetype is to be determined.
|
||||
*
|
||||
* @return This method returns true if the file format is currently
|
||||
* supported. Else it returns false.
|
||||
*/
|
||||
boolean isImageExtractionSupported(AbstractFile abstractFile) {
|
||||
boolean isContentExtractionSupported(AbstractFile abstractFile) {
|
||||
try {
|
||||
String abstractFileMimeType = fileTypeDetector.getFileType(abstractFile);
|
||||
for (SupportedImageExtractionFormats s : SupportedImageExtractionFormats.values()) {
|
||||
for (SupportedExtractionFormats s : SupportedExtractionFormats.values()) {
|
||||
if (s.toString().equals(abstractFileMimeType)) {
|
||||
abstractFileExtractionFormat = s;
|
||||
return true;
|
||||
@ -127,60 +145,55 @@ class ImageExtractor {
|
||||
}
|
||||
return false;
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
|
||||
LOGGER.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method selects the appropriate process of extracting images from
|
||||
* files using POI classes. Once the images have been extracted, the method
|
||||
* adds them to the DB and fires a ModuleContentEvent. ModuleContent Event
|
||||
* is not fired if the no images were extracted from the processed file.
|
||||
* This method selects the appropriate process of extracting embedded
|
||||
* content from files using either Tika or POI classes. Once the content has
|
||||
* been extracted as files, the method adds them to the DB and fires a
|
||||
* ModuleContentEvent. ModuleContent Event is not fired if no content
|
||||
* was extracted from the processed file.
|
||||
*
|
||||
* @param format
|
||||
* @param abstractFile The abstract file to be processed.
|
||||
*/
|
||||
void extractImage(AbstractFile abstractFile) {
|
||||
//
|
||||
// switchcase for different supported formats
|
||||
// process abstractFile according to the format by calling appropriate methods.
|
||||
|
||||
List<ExtractedImage> listOfExtractedImages = null;
|
||||
void extractEmbeddedContent(AbstractFile abstractFile) {
|
||||
List<ExtractedFile> listOfExtractedImages = null;
|
||||
List<AbstractFile> listOfExtractedImageAbstractFiles = null;
|
||||
this.parentFileName = EmbeddedFileExtractorIngestModule.getUniqueName(abstractFile);
|
||||
//check if already has derived files, skip
|
||||
|
||||
// Skip files that already have been unpacked.
|
||||
try {
|
||||
if (abstractFile.hasChildren()) {
|
||||
//check if local unpacked dir exists
|
||||
if (new File(getOutputFolderPath(parentFileName)).exists()) {
|
||||
logger.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS
|
||||
LOGGER.log(Level.INFO, "File already has been processed as it has children and local unpacked file, skipping: {0}", abstractFile.getName()); //NON-NLS
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException e) {
|
||||
logger.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
|
||||
return;
|
||||
}
|
||||
|
||||
// Call the appropriate extraction method based on mime type
|
||||
switch (abstractFileExtractionFormat) {
|
||||
case DOC:
|
||||
listOfExtractedImages = extractImagesFromDoc(abstractFile);
|
||||
break;
|
||||
case DOCX:
|
||||
listOfExtractedImages = extractImagesFromDocx(abstractFile);
|
||||
case PPTX:
|
||||
case XLSX:
|
||||
listOfExtractedImages = extractEmbeddedContentFromOOXML(abstractFile);
|
||||
break;
|
||||
case DOC:
|
||||
listOfExtractedImages = extractEmbeddedImagesFromDoc(abstractFile);
|
||||
break;
|
||||
case PPT:
|
||||
listOfExtractedImages = extractImagesFromPpt(abstractFile);
|
||||
break;
|
||||
case PPTX:
|
||||
listOfExtractedImages = extractImagesFromPptx(abstractFile);
|
||||
listOfExtractedImages = extractEmbeddedImagesFromPpt(abstractFile);
|
||||
break;
|
||||
case XLS:
|
||||
listOfExtractedImages = extractImagesFromXls(abstractFile);
|
||||
break;
|
||||
case XLSX:
|
||||
listOfExtractedImages = extractImagesFromXlsx(abstractFile);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
@ -190,13 +203,13 @@ class ImageExtractor {
|
||||
}
|
||||
// the common task of adding abstractFile to derivedfiles is performed.
|
||||
listOfExtractedImageAbstractFiles = new ArrayList<>();
|
||||
for (ExtractedImage extractedImage : listOfExtractedImages) {
|
||||
for (ExtractedFile extractedImage : listOfExtractedImages) {
|
||||
try {
|
||||
listOfExtractedImageAbstractFiles.add(fileManager.addDerivedFile(extractedImage.getFileName(), extractedImage.getLocalPath(), extractedImage.getSize(),
|
||||
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
|
||||
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
if (!listOfExtractedImages.isEmpty()) {
|
||||
@ -206,43 +219,79 @@ class ImageExtractor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract images from doc format files.
|
||||
* Extracts embedded content from OOXML documents (i.e. pptx, docx and xlsx)
|
||||
* using Tika. This will extract images and other multimedia content
|
||||
* embedded in the given file.
|
||||
*
|
||||
* @param abstractFile The file to extract content from.
|
||||
*
|
||||
* @return A list of extracted files.
|
||||
*/
|
||||
private List<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.
|
||||
*
|
||||
* @return list of extracted images. Returns null in case no images were
|
||||
* extracted.
|
||||
*/
|
||||
private List<ExtractedImage> extractImagesFromDoc(AbstractFile af) {
|
||||
private List<ExtractedFile> extractEmbeddedImagesFromDoc(AbstractFile af) {
|
||||
List<Picture> listOfAllPictures;
|
||||
|
||||
|
||||
try {
|
||||
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
|
||||
PicturesTable pictureTable = doc.getPicturesTable();
|
||||
listOfAllPictures = pictureTable.getAllPictures();
|
||||
} catch (IOException | IllegalArgumentException |
|
||||
IndexOutOfBoundsException | NullPointerException ex) {
|
||||
} catch (IOException | IllegalArgumentException
|
||||
| IndexOutOfBoundsException | NullPointerException ex) {
|
||||
// IOException:
|
||||
// Thrown when the document has issues being read.
|
||||
|
||||
|
||||
// IllegalArgumentException:
|
||||
// This will catch OldFileFormatException, which is thrown when the
|
||||
// document's format is Word 95 or older. Alternatively, this is
|
||||
// thrown when attempting to load an RTF file as a DOC file.
|
||||
// However, our code verifies the file format before ever running it
|
||||
// through the ImageExtractor. This exception gets thrown in the
|
||||
// through the EmbeddedContentExtractor. This exception gets thrown in the
|
||||
// "IN10-0137.E01" image regardless. The reason is unknown.
|
||||
|
||||
// IndexOutOfBoundsException:
|
||||
// NullPointerException:
|
||||
// These get thrown in certain images. The reason is unknown. It is
|
||||
// likely due to problems with the file formats that POI is poorly
|
||||
// handling.
|
||||
|
||||
return null;
|
||||
} catch (Throwable ex) {
|
||||
// instantiating POI containers throw RuntimeExceptions
|
||||
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -255,7 +304,7 @@ class ImageExtractor {
|
||||
if (outputFolderPath == null) {
|
||||
return null;
|
||||
}
|
||||
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||
List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
|
||||
byte[] data = null;
|
||||
for (Picture picture : listOfAllPictures) {
|
||||
String fileName = picture.suggestFullFileName();
|
||||
@ -266,99 +315,43 @@ class ImageExtractor {
|
||||
}
|
||||
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
||||
// TODO Extract more info from the Picture viz ctime, crtime, atime, mtime
|
||||
listOfExtractedImages.add(new ExtractedImage(fileName, getFileRelativePath(fileName), picture.getSize(), af));
|
||||
listOfExtractedImages.add(new ExtractedFile(fileName, getFileRelativePath(fileName), picture.getSize()));
|
||||
}
|
||||
|
||||
return listOfExtractedImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract images from docx format files.
|
||||
* Extract embedded images from ppt format files.
|
||||
*
|
||||
* @param af the file from which images are to be extracted.
|
||||
*
|
||||
* @return list of extracted images. Returns null in case no images were
|
||||
* extracted.
|
||||
*/
|
||||
private List<ExtractedImage> extractImagesFromDocx(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) {
|
||||
private List<ExtractedFile> extractEmbeddedImagesFromPpt(AbstractFile af) {
|
||||
List<HSLFPictureData> listOfAllPictures = null;
|
||||
|
||||
|
||||
try {
|
||||
HSLFSlideShow ppt = new HSLFSlideShow(new ReadContentInputStream(af));
|
||||
listOfAllPictures = ppt.getPictureData();
|
||||
} catch (IOException | IllegalArgumentException |
|
||||
IndexOutOfBoundsException ex) {
|
||||
} catch (IOException | IllegalArgumentException
|
||||
| IndexOutOfBoundsException ex) {
|
||||
// IllegalArgumentException:
|
||||
// This will catch OldFileFormatException, which is thrown when the
|
||||
// document version is unsupported. The IllegalArgumentException may
|
||||
// also get thrown for unknown reasons.
|
||||
|
||||
|
||||
// IOException:
|
||||
// Thrown when the document has issues being read.
|
||||
|
||||
// IndexOutOfBoundsException:
|
||||
// This gets thrown in certain images. The reason is unknown. It is
|
||||
// likely due to problems with the file formats that POI is poorly
|
||||
// handling.
|
||||
|
||||
return null;
|
||||
} catch (Throwable ex) {
|
||||
// instantiating POI containers throw RuntimeExceptions
|
||||
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -374,10 +367,10 @@ class ImageExtractor {
|
||||
return null;
|
||||
}
|
||||
|
||||
// extract the images to the above initialized outputFolder.
|
||||
// extract the content to the above initialized outputFolder.
|
||||
// extraction path - outputFolder/image_number.ext
|
||||
int i = 0;
|
||||
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||
List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
|
||||
byte[] data = null;
|
||||
for (HSLFPictureData pictureData : listOfAllPictures) {
|
||||
|
||||
@ -404,80 +397,19 @@ class ImageExtractor {
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
String imageName = UNKNOWN_NAME_PREFIX + i + ext; //NON-NLS
|
||||
String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + ext; //NON-NLS
|
||||
try {
|
||||
data = pictureData.getData();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
||||
listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af));
|
||||
listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
|
||||
i++;
|
||||
}
|
||||
return listOfExtractedImages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract images from pptx format files.
|
||||
*
|
||||
* @param af the file from which images are to be extracted.
|
||||
*
|
||||
* @return list of extracted images. Returns null in case no images were
|
||||
* extracted.
|
||||
*/
|
||||
private List<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.
|
||||
*
|
||||
@ -486,41 +418,37 @@ class ImageExtractor {
|
||||
* @return list of extracted images. Returns null in case no images were
|
||||
* extracted.
|
||||
*/
|
||||
private List<ExtractedImage> extractImagesFromXls(AbstractFile af) {
|
||||
private List<ExtractedFile> extractImagesFromXls(AbstractFile af) {
|
||||
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
|
||||
|
||||
|
||||
try {
|
||||
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
|
||||
listOfAllPictures = xls.getAllPictures();
|
||||
} catch (IOException | LeftoverDataException |
|
||||
RecordFormatException | IllegalArgumentException |
|
||||
IndexOutOfBoundsException ex) {
|
||||
} catch (IOException | LeftoverDataException
|
||||
| RecordFormatException | IllegalArgumentException
|
||||
| IndexOutOfBoundsException ex) {
|
||||
// IllegalArgumentException:
|
||||
// This will catch OldFileFormatException, which is thrown when the
|
||||
// document version is unsupported. The IllegalArgumentException may
|
||||
// also get thrown for unknown reasons.
|
||||
|
||||
|
||||
// IOException:
|
||||
// Thrown when the document has issues being read.
|
||||
|
||||
// LeftoverDataException:
|
||||
// This is thrown for poorly formatted files that have more data
|
||||
// than expected.
|
||||
|
||||
// RecordFormatException:
|
||||
// This is thrown for poorly formatted files that have less data
|
||||
// that expected.
|
||||
|
||||
// IllegalArgumentException:
|
||||
// IndexOutOfBoundsException:
|
||||
// These get thrown in certain images. The reason is unknown. It is
|
||||
// likely due to problems with the file formats that POI is poorly
|
||||
// handling.
|
||||
|
||||
return null;
|
||||
} catch (Throwable ex) {
|
||||
// instantiating POI containers throw RuntimeExceptions
|
||||
logger.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
|
||||
LOGGER.log(Level.SEVERE, String.format("%s%s", NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err", af.getName()), af.getName()), ex); //NON-NLS
|
||||
return null;
|
||||
}
|
||||
|
||||
@ -537,75 +465,17 @@ class ImageExtractor {
|
||||
}
|
||||
|
||||
int i = 0;
|
||||
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||
List<ExtractedFile> listOfExtractedImages = new ArrayList<>();
|
||||
byte[] data = null;
|
||||
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
|
||||
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
|
||||
String imageName = UNKNOWN_IMAGE_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
|
||||
try {
|
||||
data = pictureData.getData();
|
||||
} catch (Exception ex) {
|
||||
return null;
|
||||
}
|
||||
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
||||
listOfExtractedImages.add(new ExtractedImage(imageName, getFileRelativePath(imageName), pictureData.getData().length, af));
|
||||
i++;
|
||||
}
|
||||
return listOfExtractedImages;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract images from xlsx format files.
|
||||
*
|
||||
* @param af the file from which images are to be extracted.
|
||||
*
|
||||
* @return list of extracted images. Returns null in case no images were
|
||||
* extracted.
|
||||
*/
|
||||
private List<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));
|
||||
listOfExtractedImages.add(new ExtractedFile(imageName, getFileRelativePath(imageName), pictureData.getData().length));
|
||||
i++;
|
||||
}
|
||||
return listOfExtractedImages;
|
||||
@ -623,18 +493,17 @@ class ImageExtractor {
|
||||
try (EncodedFileOutputStream fos = new EncodedFileOutputStream(new FileOutputStream(outputPath), TskData.EncodingType.XOR1)) {
|
||||
fos.write(data);
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS
|
||||
LOGGER.log(Level.WARNING, "Could not write to the provided location: " + outputPath, ex); //NON-NLS
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets path to the output folder for image extraction. If the path does not
|
||||
* Gets path to the output folder for file extraction. If the path does not
|
||||
* exist, it is created.
|
||||
*
|
||||
* @param parentFileName name of the abstract file being processed for image
|
||||
* extraction.
|
||||
* @param parentFileName name of the abstract file being processed
|
||||
*
|
||||
* @return path to the image extraction folder for a given abstract file.
|
||||
* @return path to the file extraction folder for a given abstract file.
|
||||
*/
|
||||
private String getOutputFolderPath(String parentFileName) {
|
||||
String outputFolderPath = moduleDirAbsolute + File.separator + parentFileName;
|
||||
@ -643,7 +512,7 @@ class ImageExtractor {
|
||||
try {
|
||||
outputFilePath.mkdirs();
|
||||
} catch (SecurityException ex) {
|
||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex);
|
||||
LOGGER.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg", parentFileName), ex);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@ -665,11 +534,11 @@ class ImageExtractor {
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents the image extracted using POI methods. Currently, POI is not
|
||||
* capable of extracting ctime, crtime, mtime, and atime; these values are
|
||||
* set to 0.
|
||||
* Represents a file extracted using either Tika or POI methods. Currently,
|
||||
* POI is not capable of extracting ctime, crtime, mtime, and atime; these
|
||||
* values are set to 0.
|
||||
*/
|
||||
private static class ExtractedImage {
|
||||
private static class ExtractedFile {
|
||||
//String fileName, String localPath, long size, long ctime, long crtime,
|
||||
//long atime, long mtime, boolean isFile, AbstractFile parentFile, String rederiveDetails, String toolName, String toolVersion, String otherDetails
|
||||
|
||||
@ -680,13 +549,12 @@ class ImageExtractor {
|
||||
private final long crtime;
|
||||
private final long atime;
|
||||
private final long mtime;
|
||||
private final AbstractFile parentFile;
|
||||
|
||||
ExtractedImage(String fileName, String localPath, long size, AbstractFile parentFile) {
|
||||
this(fileName, localPath, size, 0, 0, 0, 0, parentFile);
|
||||
ExtractedFile(String fileName, String localPath, long size) {
|
||||
this(fileName, localPath, size, 0, 0, 0, 0);
|
||||
}
|
||||
|
||||
ExtractedImage(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime, AbstractFile parentFile) {
|
||||
ExtractedFile(String fileName, String localPath, long size, long ctime, long crtime, long atime, long mtime) {
|
||||
this.fileName = fileName;
|
||||
this.localPath = localPath;
|
||||
this.size = size;
|
||||
@ -694,7 +562,6 @@ class ImageExtractor {
|
||||
this.crtime = crtime;
|
||||
this.atime = atime;
|
||||
this.mtime = mtime;
|
||||
this.parentFile = parentFile;
|
||||
}
|
||||
|
||||
public String getFileName() {
|
||||
@ -724,9 +591,84 @@ class ImageExtractor {
|
||||
public long getMtime() {
|
||||
return mtime;
|
||||
}
|
||||
}
|
||||
|
||||
public AbstractFile getParentFile() {
|
||||
return parentFile;
|
||||
/**
|
||||
* Our custom embedded content extractor for OOXML files. We pass an
|
||||
* instance of this class to Tika and Tika calls the parseEmbedded() method
|
||||
* when it encounters an embedded file.
|
||||
*/
|
||||
private class EmbeddedContentExtractor extends ParsingEmbeddedDocumentExtractor {
|
||||
|
||||
private int fileCount = 0;
|
||||
// Map of file name to ExtractedFile instance. This can revert to a
|
||||
// plain old list after we upgrade to Tika 1.16 or above.
|
||||
private final Map<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());
|
||||
}
|
||||
}
|
||||
}
|
@ -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
|
@ -45,8 +45,11 @@ import org.sleuthkit.datamodel.TskData;
|
||||
*/
|
||||
final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter {
|
||||
|
||||
private static final double ENTROPY_THRESHOLD = 7.5;
|
||||
private static final int FILE_SIZE_THRESHOLD = 5242880; // 5MB
|
||||
static final double DEFAULT_CONFIG_MINIMUM_ENTROPY = 7.5;
|
||||
static final int DEFAULT_CONFIG_MINIMUM_FILE_SIZE = 5242880; // 5MB;
|
||||
static final boolean DEFAULT_CONFIG_FILE_SIZE_MULTIPLE_ENFORCED = true;
|
||||
static final boolean DEFAULT_CONFIG_SLACK_FILES_ALLOWED = true;
|
||||
|
||||
private static final int FILE_SIZE_MODULUS = 512;
|
||||
private static final double ONE_OVER_LOG2 = 1.4426950408889634073599246810019; // (1 / log(2))
|
||||
private static final int BYTE_OCCURENCES_BUFFER_SIZE = 256;
|
||||
@ -55,13 +58,24 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
||||
private final Logger LOGGER = SERVICES.getLogger(EncryptionDetectionModuleFactory.getModuleName());
|
||||
private FileTypeDetector fileTypeDetector;
|
||||
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
|
||||
* that are encrypted and create blackboard artifacts as appropriate.
|
||||
* Create a EncryptionDetectionFileIngestModule object that will detect
|
||||
* files that are encrypted and create blackboard artifacts as appropriate.
|
||||
* The supplied EncryptionDetectionIngestJobSettings object is used to
|
||||
* configure the module.
|
||||
*/
|
||||
EncryptionDetectionFileIngestModule() {
|
||||
EncryptionDetectionFileIngestModule(EncryptionDetectionIngestJobSettings settings) {
|
||||
minimumEntropy = settings.getMinimumEntropy();
|
||||
minimumFileSize = settings.getMinimumFileSize();
|
||||
fileSizeMultipleEnforced = settings.isFileSizeMultipleEnforced();
|
||||
slackFilesAllowed = settings.isSlackFilesAllowed();
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -120,7 +134,7 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
||||
*/
|
||||
StringBuilder detailsSb = new StringBuilder();
|
||||
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(),
|
||||
"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)
|
||||
&& !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS)
|
||||
&& !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.VIRTUAL_DIR)
|
||||
&& !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)) {
|
||||
&& !file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL_DIR)
|
||||
&& (!file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK) || slackFilesAllowed)) {
|
||||
/*
|
||||
* Qualify the file against hash databases.
|
||||
*/
|
||||
@ -168,17 +183,19 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
||||
* Qualify the size.
|
||||
*/
|
||||
long contentSize = file.getSize();
|
||||
if (contentSize >= FILE_SIZE_THRESHOLD && (contentSize % FILE_SIZE_MODULUS) == 0) {
|
||||
/*
|
||||
* Qualify the MIME type.
|
||||
*/
|
||||
try {
|
||||
String mimeType = fileTypeDetector.getFileType(file);
|
||||
if (mimeType != null && mimeType.equals("application/octet-stream")) {
|
||||
possiblyEncrypted = true;
|
||||
if (contentSize >= minimumFileSize) {
|
||||
if (!fileSizeMultipleEnforced || (contentSize % FILE_SIZE_MODULUS) == 0) {
|
||||
/*
|
||||
* Qualify the MIME type.
|
||||
*/
|
||||
try {
|
||||
String mimeType = fileTypeDetector.getFileType(file);
|
||||
if (mimeType != null && mimeType.equals("application/octet-stream")) {
|
||||
possiblyEncrypted = true;
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
throw new TskCoreException("Failed to detect the file type.", ex);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
throw new TskCoreException("Failed to detect the file type.", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -186,8 +203,8 @@ final class EncryptionDetectionFileIngestModule extends FileIngestModuleAdapter
|
||||
|
||||
if (possiblyEncrypted) {
|
||||
try {
|
||||
entropy = calculateEntropy(file);
|
||||
if (entropy > ENTROPY_THRESHOLD) {
|
||||
calculatedEntropy = calculateEntropy(file);
|
||||
if (calculatedEntropy >= minimumEntropy) {
|
||||
return true;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
@ -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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</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, "{key}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
</Component>
|
||||
</SubComponents>
|
||||
</Form>
|
@ -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
|
||||
}
|
@ -22,10 +22,12 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.util.lookup.ServiceProvider;
|
||||
import org.sleuthkit.autopsy.coreutils.Version;
|
||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
|
||||
import org.sleuthkit.autopsy.ingest.FileIngestModule;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleGlobalSettingsPanel;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettingsPanel;
|
||||
|
||||
/**
|
||||
* A factory that creates file ingest modules that detect encryption.
|
||||
@ -33,9 +35,9 @@ import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
||||
@ServiceProvider(service = IngestModuleFactory.class)
|
||||
@Messages({
|
||||
"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
|
||||
public String getModuleDisplayName() {
|
||||
@ -44,7 +46,7 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter
|
||||
|
||||
/**
|
||||
* Get the name of the module.
|
||||
*
|
||||
*
|
||||
* @return The module name.
|
||||
*/
|
||||
static String getModuleName() {
|
||||
@ -67,7 +69,48 @@ public class EncryptionDetectionModuleFactory extends IngestModuleFactoryAdapter
|
||||
}
|
||||
|
||||
@Override
|
||||
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings ingestOptions) {
|
||||
return new EncryptionDetectionFileIngestModule();
|
||||
public FileIngestModule createFileIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
if (!(settings instanceof EncryptionDetectionIngestJobSettings)) {
|
||||
throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings.");
|
||||
}
|
||||
return new EncryptionDetectionFileIngestModule((EncryptionDetectionIngestJobSettings) settings);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasGlobalSettingsPanel() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestModuleGlobalSettingsPanel getGlobalSettingsPanel() {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestModuleIngestJobSettings getDefaultIngestJobSettings() {
|
||||
return new EncryptionDetectionIngestJobSettings();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasIngestJobSettingsPanel() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public IngestModuleIngestJobSettingsPanel getIngestJobSettingsPanel(IngestModuleIngestJobSettings settings) {
|
||||
if (!(settings instanceof EncryptionDetectionIngestJobSettings)) {
|
||||
throw new IllegalArgumentException("Expected settings argument to be an instance of EncryptionDetectionIngestJobSettings");
|
||||
}
|
||||
return new EncryptionDetectionIngestJobSettingsPanel((EncryptionDetectionIngestJobSettings) settings);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isDataSourceIngestModuleFactory() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) {
|
||||
throw new UnsupportedOperationException();
|
||||
}
|
||||
}
|
||||
|
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.modules.filetypeid;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
@ -27,7 +28,9 @@ import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import java.util.stream.Collectors;
|
||||
import org.apache.tika.Tika;
|
||||
import org.apache.tika.io.TikaInputStream;
|
||||
import org.apache.tika.mime.MimeTypes;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
||||
@ -36,6 +39,7 @@ import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.ReadContentInputStream;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ -50,8 +54,6 @@ public class FileTypeDetector {
|
||||
|
||||
private static final Logger logger = Logger.getLogger(FileTypeDetector.class.getName());
|
||||
private static final Tika tika = new Tika();
|
||||
private static final int BUFFER_SIZE = 64 * 1024;
|
||||
private final byte buffer[] = new byte[BUFFER_SIZE];
|
||||
private final List<FileType> userDefinedFileTypes;
|
||||
private final List<FileType> autopsyDefinedFileTypes;
|
||||
private static SortedSet<String> tikaDetectedTypes;
|
||||
@ -270,17 +272,11 @@ public class FileTypeDetector {
|
||||
* bytes to Tika.
|
||||
*/
|
||||
if (null == mimeType) {
|
||||
try {
|
||||
byte buf[];
|
||||
int len = file.read(buffer, 0, BUFFER_SIZE);
|
||||
if (len < BUFFER_SIZE) {
|
||||
buf = new byte[len];
|
||||
System.arraycopy(buffer, 0, buf, 0, len);
|
||||
} else {
|
||||
buf = buffer;
|
||||
}
|
||||
String tikaType = tika.detect(buf, file.getName());
|
||||
|
||||
ReadContentInputStream stream = new ReadContentInputStream(file);
|
||||
|
||||
try (TikaInputStream tikaInputStream = TikaInputStream.get(stream)) {
|
||||
String tikaType = tika.detect(tikaInputStream, file.getName());
|
||||
|
||||
/*
|
||||
* Remove the Tika suffix from the MIME type name.
|
||||
*/
|
||||
|
@ -17,7 +17,7 @@ HashDbSearchPanel.errorField.text=Error: Not all files have been hashed.
|
||||
HashDbSearchPanel.saveBox.text=Remember Hashes
|
||||
HashDbSearchPanel.cancelButton.text=Cancel
|
||||
OpenIDE-Module-Short-Description=Hash Database Ingest Module and hash db tools
|
||||
HashDbImportDatabaseDialog.jLabel1.text=Hash Set Name:
|
||||
HashDbImportDatabaseDialog.jLabel1.text=Name:
|
||||
HashDbImportDatabaseDialog.databasePathTextField.text=
|
||||
HashDbImportDatabaseDialog.knownBadRadioButton.text=Notable
|
||||
HashDbImportDatabaseDialog.jLabel2.text=Type of database\:
|
||||
@ -39,7 +39,7 @@ HashDbCreateDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox mes
|
||||
HashDbImportDatabaseDialog.sendIngestMessagesCheckbox.text=Send ingest inbox message for each hit
|
||||
HashDbImportDatabaseDialog.hashSetNameTextField.text=
|
||||
HashDbImportDatabaseDialog.openButton.text=Open...
|
||||
HashDbCreateDatabaseDialog.jLabel3.text=Hash Set Name:
|
||||
HashDbCreateDatabaseDialog.jLabel3.text=Name:
|
||||
HashDbCreateDatabaseDialog.okButton.text=OK
|
||||
HashDbCreateDatabaseDialog.databasePathTextField.text=
|
||||
AddContentToHashDbAction.ContentMenu.noHashDbsConfigd=No hash databases configured
|
||||
@ -205,7 +205,7 @@ HashLookupSettingsPanel.typeLabel.text=Type:
|
||||
HashLookupSettingsPanel.locationLabel.text=Database Path:
|
||||
HashLookupSettingsPanel.hashDbLocationLabel.text=No database selected
|
||||
HashLookupSettingsPanel.hashDbNameLabel.text=No database selected
|
||||
HashLookupSettingsPanel.nameLabel.text=Hash Set Name:
|
||||
HashLookupSettingsPanel.nameLabel.text=Name:
|
||||
HashLookupSettingsPanel.hashDatabasesLabel.text=Hash Databases:
|
||||
HashLookupSettingsPanel.importDatabaseButton.toolTipText=
|
||||
HashLookupSettingsPanel.importDatabaseButton.text=Import database
|
||||
@ -229,13 +229,13 @@ HashDbImportDatabaseDialog.lbVersion.text=Version:
|
||||
HashDbImportDatabaseDialog.lbOrg.text=Source Organization:
|
||||
HashDbImportDatabaseDialog.readOnlyCheckbox.text=Make database read-only
|
||||
HashDbImportDatabaseDialog.orgButton.text=Manage Organizations
|
||||
HashDbImportDatabaseDialog.versionTextField.text=
|
||||
HashDbImportDatabaseDialog.fileTypeRadioButton.text=File
|
||||
HashDbImportDatabaseDialog.centralRepoRadioButton.text=Central Repository
|
||||
HashDbImportDatabaseDialog.jLabel4.text=Location:
|
||||
HashDbCreateDatabaseDialog.jLabel4.text=Location:
|
||||
HashDbCreateDatabaseDialog.fileTypeRadioButton.text=File
|
||||
HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Central Repository
|
||||
HashDbImportDatabaseDialog.versionTextField.text=1.0
|
||||
HashDbImportDatabaseDialog.fileTypeRadioButton.text=Local
|
||||
HashDbImportDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository)
|
||||
HashDbImportDatabaseDialog.jLabel4.text=Destination:
|
||||
HashDbCreateDatabaseDialog.jLabel4.text=Destination:
|
||||
HashDbCreateDatabaseDialog.fileTypeRadioButton.text=Local
|
||||
HashDbCreateDatabaseDialog.centralRepoRadioButton.text=Remote (Central Repository)
|
||||
HashDbCreateDatabaseDialog.lbOrg.text=Source Organization:
|
||||
HashDbCreateDatabaseDialog.orgButton.text=Manage Organizations
|
||||
HashDbCreateDatabaseDialog.databasePathLabel.text=Database Path:
|
||||
|
@ -33,6 +33,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamGlobalSet;
|
||||
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
|
||||
@ -154,8 +155,12 @@ final class HashDbCreateDatabaseDialog extends javax.swing.JDialog {
|
||||
orgs = dbManager.getOrganizations();
|
||||
orgs.forEach((org) -> {
|
||||
orgComboBox.addItem(org.getName());
|
||||
if(EamDbUtil.isDefaultOrg(org)){
|
||||
orgComboBox.setSelectedItem(org.getName());
|
||||
selectedOrg = org;
|
||||
}
|
||||
});
|
||||
if (!orgs.isEmpty()) {
|
||||
if ((selectedOrg == null) && (!orgs.isEmpty())) {
|
||||
selectedOrg = orgs.get(0);
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
|
@ -33,17 +33,37 @@
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="0" pref="325" max="32767" attributes="0"/>
|
||||
<Component id="okButton" linkSize="1" min="-2" max="-2" 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"/>
|
||||
<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 type="102" alignment="1" attributes="0">
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Group type="102" 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">
|
||||
<Component id="lbOrg" min="-2" 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"/>
|
||||
<Component id="orgButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
@ -52,96 +72,87 @@
|
||||
<Component id="jLabel1" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbVersion" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="2" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<EmptySpace min="-2" pref="40" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="1" attributes="0">
|
||||
<Component id="versionTextField" max="32767" attributes="0"/>
|
||||
<Component id="hashSetNameTextField" max="32767" attributes="0"/>
|
||||
</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>
|
||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||
<Component id="cancelButton" linkSize="1" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="openButton" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<Group type="102" attributes="0">
|
||||
<Group type="103" groupAlignment="0" 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"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="knownBadRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
</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>
|
||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||
<EmptySpace max="32767" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
</Group>
|
||||
</DimensionLayout>
|
||||
<DimensionLayout dim="1">
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" alignment="1" attributes="0">
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace max="-2" 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="jLabel3" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="openButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="versionTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbVersion" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="9" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="orgButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="orgComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbOrg" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace 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 max="32767" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="okButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="cancelButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="0" attributes="0">
|
||||
<Group type="102" 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="jLabel1" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="hashSetNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="lbVersion" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="versionTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace min="-2" pref="5" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" attributes="0">
|
||||
<Component id="orgButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="orgComboBox" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
<Component id="lbOrg" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||
</Group>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="jLabel2" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
<Component id="knownRadioButton" min="-2" max="-2" attributes="0"/>
|
||||
<EmptySpace 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>
|
||||
<EmptySpace max="-2" attributes="0"/>
|
||||
</Group>
|
||||
|
@ -34,6 +34,7 @@ import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDb;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbException;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamDbUtil;
|
||||
import org.sleuthkit.autopsy.centralrepository.datamodel.EamOrganization;
|
||||
import org.sleuthkit.autopsy.centralrepository.optionspanel.ManageOrganizationsDialog;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -84,25 +85,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
||||
private void initFileChooser() {
|
||||
fileChooser.setDragEnabled(false);
|
||||
fileChooser.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||
updateFileChooserFilter();
|
||||
String[] EXTENSION = new String[]{"txt", "kdb", "idx", "hash", "Hash", "hsh"}; //NON-NLS
|
||||
FileNameExtensionFilter filter = new FileNameExtensionFilter(
|
||||
NbBundle.getMessage(this.getClass(), "HashDbImportDatabaseDialog.fileNameExtFilter.text"), EXTENSION);
|
||||
fileChooser.setFileFilter(filter);
|
||||
fileChooser.setMultiSelectionEnabled(false);
|
||||
}
|
||||
|
||||
@NbBundle.Messages({"HashDbImportDatabaseDialog.centralRepoExtFilter.text=Hash Database File (.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() {
|
||||
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
@ -148,8 +136,12 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
||||
orgs = dbManager.getOrganizations();
|
||||
orgs.forEach((org) -> {
|
||||
orgComboBox.addItem(org.getName());
|
||||
if(EamDbUtil.isDefaultOrg(org)){
|
||||
orgComboBox.setSelectedItem(org.getName());
|
||||
selectedOrg = org;
|
||||
}
|
||||
});
|
||||
if (!orgs.isEmpty()) {
|
||||
if ((selectedOrg == null) && (!orgs.isEmpty())) {
|
||||
selectedOrg = orgs.get(0);
|
||||
}
|
||||
} catch (EamDbException ex) {
|
||||
@ -303,95 +295,102 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(0, 325, Short.MAX_VALUE)
|
||||
.addComponent(okButton)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel3)
|
||||
.addComponent(jLabel4))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(cancelButton))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(fileTypeRadioButton)
|
||||
.addGap(26, 26, 26)
|
||||
.addComponent(centralRepoRadioButton)
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(databasePathTextField)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openButton)
|
||||
.addContainerGap())))
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(sendIngestMessagesCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(okButton))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addComponent(lbOrg)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(orgComboBox, 0, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addComponent(orgComboBox, 0, 121, Short.MAX_VALUE)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(orgButton))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(lbVersion))
|
||||
.addGap(2, 2, 2)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGap(40, 40, 40)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.TRAILING)
|
||||
.addComponent(versionTextField)
|
||||
.addComponent(hashSetNameTextField)))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel3)
|
||||
.addComponent(jLabel4))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addComponent(fileTypeRadioButton)
|
||||
.addGap(26, 26, 26)
|
||||
.addComponent(centralRepoRadioButton))
|
||||
.addComponent(databasePathTextField))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(openButton))
|
||||
.addComponent(hashSetNameTextField))))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
.addComponent(cancelButton)
|
||||
.addContainerGap())
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(jLabel2)
|
||||
.addComponent(readOnlyCheckbox)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGap(19, 19, 19)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(knownRadioButton)
|
||||
.addComponent(knownBadRadioButton)))
|
||||
.addComponent(sendIngestMessagesCheckbox)
|
||||
.addComponent(readOnlyCheckbox))
|
||||
.addGap(0, 0, Short.MAX_VALUE)))
|
||||
.addContainerGap())
|
||||
.addComponent(knownBadRadioButton))))
|
||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))))
|
||||
);
|
||||
|
||||
layout.linkSize(javax.swing.SwingConstants.HORIZONTAL, new java.awt.Component[] {cancelButton, okButton});
|
||||
|
||||
layout.setVerticalGroup(
|
||||
layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addContainerGap()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(fileTypeRadioButton)
|
||||
.addComponent(centralRepoRadioButton)
|
||||
.addComponent(jLabel4))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(openButton)
|
||||
.addComponent(databasePathTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(jLabel3))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbVersion))
|
||||
.addGap(9, 9, 9)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(orgButton)
|
||||
.addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbOrg))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(knownRadioButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(knownBadRadioButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(readOnlyCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sendIngestMessagesCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(okButton)
|
||||
.addComponent(cancelButton))
|
||||
.addComponent(jLabel3)
|
||||
.addComponent(openButton))
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(layout.createSequentialGroup()
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(fileTypeRadioButton)
|
||||
.addComponent(centralRepoRadioButton)
|
||||
.addComponent(jLabel4))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(jLabel1)
|
||||
.addComponent(hashSetNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(lbVersion)
|
||||
.addComponent(versionTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addGap(5, 5, 5)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(orgButton)
|
||||
.addComponent(orgComboBox, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(lbOrg))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(jLabel2)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(knownRadioButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(knownBadRadioButton)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(readOnlyCheckbox)
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||
.addComponent(sendIngestMessagesCheckbox)
|
||||
.addGap(0, 21, Short.MAX_VALUE))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
|
||||
.addGap(0, 0, Short.MAX_VALUE)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.addComponent(cancelButton)
|
||||
.addComponent(okButton))))
|
||||
.addContainerGap())
|
||||
);
|
||||
|
||||
@ -409,7 +408,6 @@ final class HashDbImportDatabaseDialog extends javax.swing.JDialog {
|
||||
hashDbFolder.mkdir();
|
||||
}
|
||||
fileChooser.setCurrentDirectory(hashDbFolder);
|
||||
updateFileChooserFilter();
|
||||
if (fileChooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) {
|
||||
File databaseFile = fileChooser.getSelectedFile();
|
||||
try {
|
||||
|
@ -105,28 +105,6 @@
|
||||
<Group type="102" attributes="0">
|
||||
<EmptySpace min="10" pref="10" max="-2" 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="103" groupAlignment="0" 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"/>
|
||||
<Component id="addHashesToDatabaseButton" min="-2" max="-2" attributes="0"/>
|
||||
</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 type="102" alignment="0" attributes="0">
|
||||
|
@ -787,24 +787,6 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(10, 10, 10)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(locationLabel)
|
||||
.addComponent(typeLabel)
|
||||
.addComponent(versionLabel)
|
||||
.addComponent(orgLabel)
|
||||
.addComponent(readOnlyLabel))
|
||||
.addGap(55, 55, 55)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(hashDbVersionLabel)
|
||||
.addComponent(hashDbOrgLabel)
|
||||
.addComponent(hashDbReadOnlyLabel)))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addComponent(nameLabel)
|
||||
.addGap(53, 53, 53)
|
||||
.addComponent(hashDbNameLabel))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(indexLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 66, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
@ -816,7 +798,23 @@ public final class HashLookupSettingsPanel extends IngestModuleGlobalSettingsPan
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addComponent(indexButton, javax.swing.GroupLayout.PREFERRED_SIZE, 120, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addGap(10, 10, 10)
|
||||
.addComponent(addHashesToDatabaseButton))))
|
||||
.addComponent(addHashesToDatabaseButton))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(locationLabel)
|
||||
.addComponent(typeLabel)
|
||||
.addComponent(versionLabel)
|
||||
.addComponent(orgLabel)
|
||||
.addComponent(readOnlyLabel)
|
||||
.addComponent(nameLabel))
|
||||
.addGap(55, 55, 55)
|
||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||
.addComponent(hashDbNameLabel)
|
||||
.addComponent(hashDbTypeLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(hashDbLocationLabel, javax.swing.GroupLayout.PREFERRED_SIZE, 225, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||
.addComponent(hashDbVersionLabel)
|
||||
.addComponent(hashDbOrgLabel)
|
||||
.addComponent(hashDbReadOnlyLabel)))))
|
||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||
.addGap(70, 70, 70)
|
||||
.addComponent(informationSeparator, javax.swing.GroupLayout.PREFERRED_SIZE, 305, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -28,7 +28,8 @@ import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
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 {
|
||||
|
||||
@ -49,6 +50,7 @@ class IdxHashSetParser implements HashSetParser {
|
||||
File importFile = new File(filename);
|
||||
long fileSize = importFile.length();
|
||||
totalHashes = fileSize / 0x33 + 1; // IDX file lines are generally 0x33 bytes long. We add one to prevent this from being zero
|
||||
// MD5sum output lines should be close enough to that (0x20 byte hash + filename)
|
||||
}
|
||||
|
||||
/**
|
||||
@ -65,14 +67,15 @@ class IdxHashSetParser implements HashSetParser {
|
||||
try {
|
||||
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
|
||||
if (parts.length != 2 || parts[0].length() == 41) {
|
||||
String hashStr = parts[0].toLowerCase();
|
||||
if (!hashStr.matches("^[0-9a-f]{32}$")) {
|
||||
continue;
|
||||
}
|
||||
|
||||
return parts[0].toLowerCase();
|
||||
return hashStr;
|
||||
}
|
||||
} catch (IOException ex) {
|
||||
throw new TskCoreException("Error reading file " + filename, ex);
|
||||
|
@ -213,12 +213,14 @@ class ImportCentralRepoDbProgressDialog extends javax.swing.JDialog implements P
|
||||
|
||||
// Create the hash set parser
|
||||
HashSetParser hashSetParser;
|
||||
if (importFileName.toLowerCase().endsWith(".idx")) {
|
||||
if (importFileName.toLowerCase().endsWith(".idx") || importFileName.toLowerCase().endsWith(".txt")) {
|
||||
hashSetParser = new IdxHashSetParser(importFileName);
|
||||
} else if(importFileName.toLowerCase().endsWith(".hash")){
|
||||
} else if (importFileName.toLowerCase().endsWith(".hash")) {
|
||||
hashSetParser = new EncaseHashSetParser(importFileName);
|
||||
} else if(importFileName.toLowerCase().endsWith(".kdb")){
|
||||
} else if (importFileName.toLowerCase().endsWith(".kdb")) {
|
||||
hashSetParser = new KdbHashSetParser(importFileName);
|
||||
} else if (importFileName.toLowerCase().endsWith(".hsh")) {
|
||||
hashSetParser = new HashkeeperHashSetParser(importFileName);
|
||||
} else {
|
||||
// We've gotten here with a format that can't be processed
|
||||
throw new TskCoreException("Hash set to import is an unknown format : " + importFileName);
|
||||
|
@ -63,6 +63,7 @@ import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
|
||||
class ReportHTML implements TableReportModule {
|
||||
@ -688,7 +689,8 @@ class ReportHTML implements TableReportModule {
|
||||
}
|
||||
for (int i = 0; i < tags.size(); i++) {
|
||||
ContentTag tag = tags.get(i);
|
||||
linkToThumbnail.append(tag.getName().getDisplayName());
|
||||
String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
linkToThumbnail.append(tag.getName().getDisplayName() + notableString);
|
||||
if (i != tags.size() - 1) {
|
||||
linkToThumbnail.append(", ");
|
||||
}
|
||||
|
@ -41,10 +41,12 @@ import javax.swing.event.ListDataListener;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
final class ReportVisualPanel2 extends JPanel {
|
||||
|
||||
@ -102,7 +104,8 @@ final class ReportVisualPanel2 extends JPanel {
|
||||
}
|
||||
|
||||
for (TagName tagName : tagNamesInUse) {
|
||||
tagStates.put(tagName.getDisplayName(), Boolean.FALSE);
|
||||
String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
tagStates.put(tagName.getDisplayName() + notableString, Boolean.FALSE);
|
||||
}
|
||||
tags.addAll(tagStates.keySet());
|
||||
|
||||
|
@ -39,6 +39,7 @@ import java.util.TreeSet;
|
||||
import java.util.logging.Level;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.EscapeUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
@ -299,7 +300,8 @@ class TableReportGenerator {
|
||||
// Give the modules the rows for the content tags.
|
||||
for (ContentTag tag : tags) {
|
||||
// skip tags that we are not reporting on
|
||||
if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) {
|
||||
String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
@ -310,7 +312,7 @@ class TableReportGenerator {
|
||||
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();
|
||||
if (content instanceof AbstractFile) {
|
||||
AbstractFile file = (AbstractFile) content;
|
||||
@ -376,12 +378,13 @@ class TableReportGenerator {
|
||||
|
||||
// Give the modules the rows for the content tags.
|
||||
for (BlackboardArtifactTag tag : tags) {
|
||||
if (passesTagNamesFilter(tag.getName().getDisplayName()) == false) {
|
||||
String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
if (passesTagNamesFilter(tag.getName().getDisplayName() + notableString) == false) {
|
||||
continue;
|
||||
}
|
||||
|
||||
List<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);
|
||||
|
||||
// check if the tag is an image that we should later make a thumbnail for
|
||||
@ -963,7 +966,8 @@ class TableReportGenerator {
|
||||
try {
|
||||
List<ContentTag> contentTags = Case.getCurrentCase().getServices().getTagsManager().getContentTagsByContent(content);
|
||||
for (ContentTag ct : contentTags) {
|
||||
allTags.add(ct.getName().getDisplayName());
|
||||
String notableString = ct.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
allTags.add(ct.getName().getDisplayName() + notableString);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
errorList.add(NbBundle.getMessage(this.getClass(), "ReportGenerator.errList.failedGetContentTags"));
|
||||
@ -1000,7 +1004,8 @@ class TableReportGenerator {
|
||||
List<BlackboardArtifactTag> tags = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact);
|
||||
HashSet<String> uniqueTagNames = new HashSet<>();
|
||||
for (BlackboardArtifactTag tag : tags) {
|
||||
uniqueTagNames.add(tag.getName().getDisplayName());
|
||||
String notableString = tag.getName().getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
uniqueTagNames.add(tag.getName().getDisplayName() + notableString);
|
||||
}
|
||||
if (failsTagFilter(uniqueTagNames, tagNamesFilter)) {
|
||||
continue;
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013-16 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2013-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.
|
||||
@ -36,10 +36,12 @@ import javax.swing.SwingWorker;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.NbBundle.Messages;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.actions.GetTagNameAndCommentDialog;
|
||||
import org.sleuthkit.autopsy.actions.GetTagNameDialog;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
|
||||
@ -48,6 +50,7 @@ import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
@ -67,7 +70,8 @@ public class AddTagAction extends Action {
|
||||
this.selectedFileIDs = selectedFileIDs;
|
||||
this.tagName = tagName;
|
||||
setGraphic(controller.getTagsManager().getGraphic(tagName));
|
||||
setText(tagName.getDisplayName());
|
||||
String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
setText(tagName.getDisplayName() + notableString);
|
||||
setEventHandler(actionEvent -> addTagWithComment(""));
|
||||
}
|
||||
|
||||
@ -78,7 +82,7 @@ public class AddTagAction extends Action {
|
||||
private void addTagWithComment(String comment) {
|
||||
addTagsToFiles(tagName, comment, selectedFileIDs);
|
||||
}
|
||||
|
||||
|
||||
@NbBundle.Messages({"# {0} - fileID",
|
||||
"AddDrawableTagAction.addTagsToFiles.alert=Unable to tag file {0}."})
|
||||
private void addTagsToFiles(TagName tagName, String comment, Set<Long> selectedFiles) {
|
||||
@ -108,8 +112,8 @@ public class AddTagAction extends Action {
|
||||
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
LOGGER.log(Level.SEVERE, "Error tagging file", tskCoreException); //NON-NLS
|
||||
Platform.runLater(() ->
|
||||
new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show()
|
||||
Platform.runLater(()
|
||||
-> new Alert(Alert.AlertType.ERROR, Bundle.AddDrawableTagAction_addTagsToFiles_alert(fileID)).show()
|
||||
);
|
||||
break;
|
||||
}
|
||||
@ -172,8 +176,8 @@ public class AddTagAction extends Action {
|
||||
* or select a tag name and adds a tag with the resulting name.
|
||||
*/
|
||||
MenuItem newTagMenuItem = new MenuItem(Bundle.AddTagAction_menuItem_newTag());
|
||||
newTagMenuItem.setOnAction(actionEvent ->
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
newTagMenuItem.setOnAction(actionEvent
|
||||
-> SwingUtilities.invokeLater(() -> {
|
||||
TagName tagName = GetTagNameDialog.doDialog(getIGWindow());
|
||||
if (tagName != null) {
|
||||
new AddTagAction(controller, tagName, selectedFileIDs).handle(actionEvent);
|
||||
@ -188,8 +192,8 @@ public class AddTagAction extends Action {
|
||||
* name.
|
||||
*/
|
||||
MenuItem tagAndCommentItem = new MenuItem(Bundle.AddTagAction_menuItem_tagAndComment());
|
||||
tagAndCommentItem.setOnAction(actionEvent ->
|
||||
SwingUtilities.invokeLater(() -> {
|
||||
tagAndCommentItem.setOnAction(actionEvent
|
||||
-> SwingUtilities.invokeLater(() -> {
|
||||
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog(getIGWindow());
|
||||
if (null != tagNameAndComment) {
|
||||
new AddTagAction(controller, tagNameAndComment.getTagName(), selectedFileIDs).addTagWithComment(tagNameAndComment.getComment());
|
||||
|
@ -1,15 +1,15 @@
|
||||
/*
|
||||
* 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.
|
||||
@ -18,7 +18,6 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.imagegallery.actions;
|
||||
|
||||
import java.awt.Window;
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Iterator;
|
||||
@ -30,24 +29,22 @@ import javafx.scene.control.Alert;
|
||||
import javafx.scene.control.Menu;
|
||||
import javafx.scene.control.MenuItem;
|
||||
import javafx.scene.image.ImageView;
|
||||
import javax.swing.SwingUtilities;
|
||||
import javax.swing.SwingWorker;
|
||||
import org.controlsfx.control.action.Action;
|
||||
import org.controlsfx.control.action.ActionUtils;
|
||||
import org.openide.util.NbBundle;
|
||||
import org.openide.util.Utilities;
|
||||
import org.openide.windows.TopComponent;
|
||||
import org.openide.windows.WindowManager;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryController;
|
||||
import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
|
||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableTagsManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TagName;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to remove tags from content.
|
||||
@ -68,7 +65,8 @@ public class DeleteTagAction extends Action {
|
||||
this.tagName = tagName;
|
||||
this.contentTag = contentTag;
|
||||
setGraphic(controller.getTagsManager().getGraphic(tagName));
|
||||
setText(tagName.getDisplayName());
|
||||
String notableString = tagName.getKnownStatus() == TskData.FileKnown.BAD ? TagsManager.getNotableTagLabel() : "";
|
||||
setText(tagName.getDisplayName() + notableString);
|
||||
setEventHandler(actionEvent -> deleteTag());
|
||||
}
|
||||
|
||||
@ -84,20 +82,20 @@ public class DeleteTagAction extends Action {
|
||||
@Override
|
||||
protected Void doInBackground() throws Exception {
|
||||
DrawableTagsManager tagsManager = controller.getTagsManager();
|
||||
|
||||
|
||||
// Pull the from the global context to avoid unnecessary calls
|
||||
// to the database.
|
||||
final Collection<AbstractFile> selectedFilesList =
|
||||
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
final Collection<AbstractFile> selectedFilesList
|
||||
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
AbstractFile file = selectedFilesList.iterator().next();
|
||||
|
||||
|
||||
try {
|
||||
LOGGER.log(Level.INFO, "Removing tag {0} from {1}", new Object[]{tagName.getDisplayName(), file.getName()}); //NON-NLS
|
||||
tagsManager.deleteContentTag(contentTag);
|
||||
} catch (TskCoreException tskCoreException) {
|
||||
LOGGER.log(Level.SEVERE, "Error untagging file", tskCoreException); //NON-NLS
|
||||
Platform.runLater(() ->
|
||||
new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show()
|
||||
Platform.runLater(()
|
||||
-> new Alert(Alert.AlertType.ERROR, Bundle.DeleteDrawableTagAction_deleteTag_alert(fileId)).show()
|
||||
);
|
||||
}
|
||||
return null;
|
||||
@ -121,25 +119,25 @@ public class DeleteTagAction extends Action {
|
||||
TagMenu(ImageGalleryController controller) {
|
||||
setGraphic(new ImageView(DrawableAttribute.TAGS.getIcon()));
|
||||
setText(Bundle.DeleteDrawableTagAction_displayName());
|
||||
|
||||
|
||||
// For this menu, we shouldn't have more than one file selected.
|
||||
// Therefore, we will simply grab the first file and work with that.
|
||||
final Collection<AbstractFile> selectedFilesList =
|
||||
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
final Collection<AbstractFile> selectedFilesList
|
||||
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||
AbstractFile file = selectedFilesList.iterator().next();
|
||||
|
||||
try {
|
||||
List<ContentTag> existingTagsList =
|
||||
Case.getCurrentCase().getServices().getTagsManager()
|
||||
.getContentTagsByContent(file);
|
||||
|
||||
Collection<TagName> tagNamesList =
|
||||
controller.getTagsManager().getNonCategoryTagNames();
|
||||
try {
|
||||
List<ContentTag> existingTagsList
|
||||
= Case.getCurrentCase().getServices().getTagsManager()
|
||||
.getContentTagsByContent(file);
|
||||
|
||||
Collection<TagName> tagNamesList
|
||||
= controller.getTagsManager().getNonCategoryTagNames();
|
||||
Iterator<TagName> tagNameIterator = tagNamesList.iterator();
|
||||
for(int i=0; tagNameIterator.hasNext(); i++) {
|
||||
for (int i = 0; tagNameIterator.hasNext(); i++) {
|
||||
TagName tagName = tagNameIterator.next();
|
||||
for(ContentTag contentTag : existingTagsList) {
|
||||
if(contentTag.getName().getId() == tagName.getId()) {
|
||||
for (ContentTag contentTag : existingTagsList) {
|
||||
if (contentTag.getName().getId() == tagName.getId()) {
|
||||
DeleteTagAction deleteDrawableTagAction = new DeleteTagAction(controller, tagName, contentTag, file.getId());
|
||||
MenuItem tagNameItem = ActionUtils.createMenuItem(deleteDrawableTagAction);
|
||||
getItems().add(tagNameItem);
|
||||
@ -151,7 +149,7 @@ public class DeleteTagAction extends Action {
|
||||
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
|
||||
}
|
||||
|
||||
if(getItems().isEmpty()) {
|
||||
if (getItems().isEmpty()) {
|
||||
setDisable(true);
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user