mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Merge branch 'release-4.4.0' of https://github.com/sleuthkit/autopsy into develop
This commit is contained in:
commit
a23543a72d
@ -34,6 +34,13 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
/**
|
/**
|
||||||
* Instances of this Action allow users to apply tags to blackboard artifacts.
|
* Instances of this Action allow users to apply tags to blackboard artifacts.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AddBlackboardArtifactTagAction.singularTagResult=Tag Result",
|
||||||
|
"AddBlackboardArtifactTagAction.pluralTagResult=Tag Results",
|
||||||
|
"# {0} - artifactName",
|
||||||
|
"AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.",
|
||||||
|
"AddBlackboardArtifactTagAction.taggingErr=Tagging Error"
|
||||||
|
})
|
||||||
public class AddBlackboardArtifactTagAction extends AddTagAction {
|
public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||||
|
|
||||||
// This class is a singleton to support multi-selection of nodes, since
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2016 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -29,15 +29,24 @@ import org.sleuthkit.autopsy.casemodule.Case;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.FsContent;
|
|
||||||
import org.sleuthkit.datamodel.LayoutFile;
|
|
||||||
import org.sleuthkit.datamodel.LocalFile;
|
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this Action allow users to apply tags to content.
|
* Instances of this Action allow users to apply tags to content.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AddContentTagAction.singularTagFile=Tag File",
|
||||||
|
"AddContentTagAction.pluralTagFile=Tag Files",
|
||||||
|
"# {0} - fileName",
|
||||||
|
"AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.",
|
||||||
|
"AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag",
|
||||||
|
"# {0} - fileName",
|
||||||
|
"AddContentTagAction.unableToTag.msg2=Unable to tag {0}.",
|
||||||
|
"AddContentTagAction.taggingErr=Tagging Error",
|
||||||
|
"# {0} - fileName", "# {1} - tagName",
|
||||||
|
"AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag."
|
||||||
|
})
|
||||||
public class AddContentTagAction extends AddTagAction {
|
public class AddContentTagAction extends AddTagAction {
|
||||||
|
|
||||||
// This class is a singleton to support multi-selection of nodes, since
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
|
@ -14,29 +14,12 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment:
|
|||||||
GetTagNameAndCommentDialog.cancelButton.text=Cancel
|
GetTagNameAndCommentDialog.cancelButton.text=Cancel
|
||||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||||
GetTagNameAndCommentDialog.tagLabel.text=Tag:
|
GetTagNameAndCommentDialog.tagLabel.text=Tag:
|
||||||
AddBlackboardArtifactTagAction.singularTagResult=Tag Result
|
|
||||||
AddBlackboardArtifactTagAction.pluralTagResult=Tag Results
|
|
||||||
AddBlackboardArtifactTagAction.unableToTag.msg=Unable to tag {0}.
|
|
||||||
AddBlackboardArtifactTagAction.taggingErr=Tagging Error
|
|
||||||
AddContentTagAction.singularTagFile=Tag File
|
|
||||||
AddContentTagAction.pluralTagFile=Tag Files
|
|
||||||
AddContentTagAction.unableToTag.msg=Unable to tag {0}, not a regular file.
|
|
||||||
AddContentTagAction.cannotApplyTagErr=Cannot Apply Tag
|
|
||||||
AddContentTagAction.unableToTag.msg2=Unable to tag {0}.
|
|
||||||
AddContentTagAction.taggingErr=Tagging Error
|
|
||||||
AddContentTagAction.tagExists={0} has been tagged as {1}. Cannot reapply the same tag.
|
|
||||||
AddTagAction.bookmarkFile=Bookmark file
|
AddTagAction.bookmarkFile=Bookmark file
|
||||||
AddTagAction.quickTag=Quick Tag
|
AddTagAction.quickTag=Quick Tag
|
||||||
AddTagAction.noTags=No tags
|
AddTagAction.noTags=No tags
|
||||||
AddTagAction.newTag=New Tag...
|
AddTagAction.newTag=New Tag...
|
||||||
AddTagAction.tagAndComment=Tag and Comment...
|
AddTagAction.tagAndComment=Tag and Comment...
|
||||||
AddBookmarkTagAction.bookmark.text=Bookmark
|
AddBookmarkTagAction.bookmark.text=Bookmark
|
||||||
DeleteBlackboardArtifactTagAction.deleteTags=Delete Tag(s)
|
|
||||||
DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
|
||||||
DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error
|
|
||||||
DeleteContentTagAction.deleteTags=Delete Tag(s)
|
|
||||||
DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.
|
|
||||||
DeleteContentTagAction.tagDelErr=Tag Deletion Error
|
|
||||||
GetTagNameAndCommentDialog.noTags=No Tags
|
GetTagNameAndCommentDialog.noTags=No Tags
|
||||||
GetTagNameAndCommentDialog.createTag=Create Tag
|
GetTagNameAndCommentDialog.createTag=Create Tag
|
||||||
GetTagNameAndCommentDialog.cancelName=cancel
|
GetTagNameAndCommentDialog.cancelName=cancel
|
||||||
|
@ -1,57 +1,51 @@
|
|||||||
GetTagNameDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB
|
GetTagNameDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||||
GetTagNameDialog.okButton.text=OK
|
GetTagNameDialog.okButton.text=OK
|
||||||
GetTagNameDialog.preexistingLabel.text=\u65E2\u5B58\u30BF\u30B0\uFF1A
|
GetTagNameDialog.preexistingLabel.text=\u65e2\u5b58\u30bf\u30b0\uff1a
|
||||||
GetTagNameDialog.newTagPanel.border.title=\u65B0\u898F\u30BF\u30B0
|
GetTagNameDialog.newTagPanel.border.title=\u65b0\u898f\u30bf\u30b0
|
||||||
GetTagNameDialog.tagNameLabel.text=\u30BF\u30B0\u540D\uFF1A
|
GetTagNameDialog.tagNameLabel.text=\u30bf\u30b0\u540d\uff1a
|
||||||
GetTagNameAndCommentDialog.newTagButton.text=\u65B0\u898F\u30BF\u30B0
|
GetTagNameAndCommentDialog.newTagButton.text=\u65b0\u898f\u30bf\u30b0
|
||||||
GetTagNameAndCommentDialog.okButton.text=OK
|
GetTagNameAndCommentDialog.okButton.text=OK
|
||||||
GetTagNameAndCommentDialog.commentText.toolTipText=\u30BF\u30B0\u306E\u30AA\u30D7\u30B7\u30E7\u30CA\u30EB\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u5165\u529B\u307E\u305F\u306F\u7A7A\u6B04\u306B\u3057\u3066\u304F\u3060\u3055\u3044
|
GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044
|
||||||
GetTagNameAndCommentDialog.commentLabel.text=\u30B3\u30E1\u30F3\u30C8\uFF1A
|
GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a
|
||||||
GetTagNameAndCommentDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB
|
GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||||
GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4F7F\u7528\u3059\u308B\u30BF\u30B0\u3092\u9078\u629E
|
GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e
|
||||||
GetTagNameAndCommentDialog.tagLabel.text=\u30BF\u30B0\uFF1A
|
GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a
|
||||||
AddBlackboardArtifactTagAction.singularTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
|
AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||||
AddBlackboardArtifactTagAction.pluralTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
|
AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||||
AddBlackboardArtifactTagAction.unableToTag.msg={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002
|
AddBlackboardArtifactTagAction.unableToTag.msg={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002
|
||||||
AddBlackboardArtifactTagAction.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC
|
AddBlackboardArtifactTagAction.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc
|
||||||
AddContentTagAction.singularTagFile=\u30D5\u30A1\u30A4\u30EB\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
|
AddContentTagAction.singularTagFile=\u30d5\u30a1\u30a4\u30eb\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||||
AddContentTagAction.pluralTagFile=\u30D5\u30A1\u30A4\u30EB\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
|
AddContentTagAction.pluralTagFile=\u30d5\u30a1\u30a4\u30eb\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
|
||||||
AddContentTagAction.unableToTag.msg={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002\u901A\u5E38\u30D5\u30A1\u30A4\u30EB\u3067\u306F\u3042\u308A\u307E\u305B\u3093\u3002
|
AddContentTagAction.unableToTag.msg={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002\u901a\u5e38\u30d5\u30a1\u30a4\u30eb\u3067\u306f\u3042\u308a\u307e\u305b\u3093\u3002
|
||||||
AddContentTagAction.unableToTag.msg2={0}\u306B\u30BF\u30B0\u3092\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3002
|
AddContentTagAction.unableToTag.msg2={0}\u306b\u30bf\u30b0\u3092\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3002
|
||||||
AddContentTagAction.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC
|
AddContentTagAction.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc
|
||||||
AddTagAction.quickTag=\u30AF\u30A4\u30C3\u30AF\u30BF\u30B0
|
AddTagAction.quickTag=\u30af\u30a4\u30c3\u30af\u30bf\u30b0
|
||||||
AddTagAction.noTags=\u30BF\u30B0\u7121\u3057
|
AddTagAction.noTags=\u30bf\u30b0\u7121\u3057
|
||||||
AddTagAction.newTag=\u65B0\u898F\u30BF\u30B0\u2026
|
AddTagAction.newTag=\u65b0\u898f\u30bf\u30b0\u2026
|
||||||
AddTagAction.tagAndComment=\u30BF\u30B0\u3068\u30B3\u30E1\u30F3\u30C8\u3092\u8FFD\u52A0\u2026
|
AddTagAction.tagAndComment=\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u2026
|
||||||
DeleteBlackboardArtifactTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664
|
GetTagNameAndCommentDialog.noTags=\u30bf\u30b0\u7121\u3057
|
||||||
DeleteBlackboardArtifactTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002
|
GetTagNameAndCommentDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210
|
||||||
DeleteBlackboardArtifactTagAction.tagDelErr=\u30BF\u30B0\u524A\u9664\u30A8\u30E9\u30FC
|
GetTagNameAndCommentDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||||
DeleteContentTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664
|
GetTagNameDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210
|
||||||
DeleteContentTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002
|
GetTagNameDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb
|
||||||
DeleteContentTagAction.tagDelErr=\u30BF\u30B0\u306E\u524A\u9664\u30A8\u30E9\u30FC
|
GetTagNameDialog.mustSupplyTtagName.msg=\u30bf\u30b0\u540d\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u5148\u306b\u9032\u3081\u307e\u305b\u3093\u3002
|
||||||
GetTagNameAndCommentDialog.noTags=\u30BF\u30B0\u7121\u3057
|
GetTagNameDialog.tagNameErr=\u30bf\u30b0\u540d
|
||||||
GetTagNameAndCommentDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210
|
GetTagNameDialog.illegalCharsErr=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57
|
||||||
GetTagNameAndCommentDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB
|
GetTagNameDialog.unableToAddTagNameToCase.msg=\u30bf\u30b0\u540d{0}\u3092\u30b1\u30fc\u30b9\u306b\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
|
||||||
GetTagNameDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210
|
GetTagNameDialog.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc
|
||||||
GetTagNameDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB
|
GetTagNameDialog.tagNameAlreadyDef.msg=\u30bf\u30b0\u540d{0}\u306f\u65e2\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059\u3002
|
||||||
GetTagNameDialog.mustSupplyTtagName.msg=\u30BF\u30B0\u540D\u3092\u6307\u5B9A\u3057\u306A\u3051\u308C\u3070\u5148\u306B\u9032\u3081\u307E\u305B\u3093\u3002
|
GetTagNameDialog.dupTagErr=\u30bf\u30b0\u306e\u91cd\u8907\u30a8\u30e9\u30fc
|
||||||
GetTagNameDialog.tagNameErr=\u30BF\u30B0\u540D
|
AddContentTagAction.cannotApplyTagErr=\u30bf\u30b0\u3092\u9069\u7528\u3067\u304d\u307e\u305b\u3093
|
||||||
GetTagNameDialog.illegalCharsErr=\u4F7F\u7528\u3067\u304D\u306A\u3044\u6587\u5B57
|
OpenLogFolder.error1=\u30ed\u30b0\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
|
||||||
GetTagNameDialog.unableToAddTagNameToCase.msg=\u30BF\u30B0\u540D{0}\u3092\u30B1\u30FC\u30B9\u306B\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002
|
CTL_OpenLogFolder=\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u3092\u958b\u304f
|
||||||
GetTagNameDialog.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC
|
ShowIngestProgressSnapshotAction.actionName.text=\u30a4\u30f3\u30b8\u30a7\u30b9\u30c8\u30d7\u30ed\u30b0\u30ec\u30b9\u306e\u30b9\u30ca\u30c3\u30d7\u30b7\u30e7\u30c3\u30c8\u3092\u53d6\u5f97
|
||||||
GetTagNameDialog.tagNameAlreadyDef.msg=\u30BF\u30B0\u540D{0}\u306F\u65E2\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059\u3002
|
CTL_OpenPythonModulesFolderAction=Python\u30d7\u30e9\u30b0\u30a4\u30f3
|
||||||
GetTagNameDialog.dupTagErr=\u30BF\u30B0\u306E\u91CD\u8907\u30A8\u30E9\u30FC
|
OpenPythonModulesFolderAction.actionName.text=Python\u30d7\u30e9\u30b0\u30a4\u30f3
|
||||||
AddContentTagAction.cannotApplyTagErr=\u30BF\u30B0\u3092\u9069\u7528\u3067\u304D\u307E\u305B\u3093
|
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python\u30d7\u30e9\u30b0\u30a4\u30f3\u30d5\u30a9\u30eb\u30c0\u30fc\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
|
||||||
OpenLogFolder.error1=\u30ED\u30B0\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0}
|
AddContentTagAction.tagExists={0}\u306f\u65e2\u306b{1}\u3068\u30bf\u30b0\u3055\u308c\u3066\u3044\u307e\u3059\u3002\u540c\u3058\u30bf\u30b0\u306f\u4f7f\u7528\u3067\u304d\u307e\u305b\u3093\u3002
|
||||||
CTL_OpenLogFolder=\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u3092\u958B\u304F
|
OpenLogFolder.CouldNotOpenLogFolder=\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u30fc\u3092\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
|
||||||
ShowIngestProgressSnapshotAction.actionName.text=\u30A4\u30F3\u30B8\u30A7\u30B9\u30C8\u30D7\u30ED\u30B0\u30EC\u30B9\u306E\u30B9\u30CA\u30C3\u30D7\u30B7\u30E7\u30C3\u30C8\u3092\u53D6\u5F97
|
CTL_OpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u3092\u3092\u958b\u304f
|
||||||
CTL_OpenPythonModulesFolderAction=Python\u30D7\u30E9\u30B0\u30A4\u30F3
|
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}
|
||||||
OpenPythonModulesFolderAction.actionName.text=Python\u30D7\u30E9\u30B0\u30A4\u30F3
|
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
|
||||||
OpenPythonModulesFolderAction.errorMsg.folderNotFound=Python\u30D7\u30E9\u30B0\u30A4\u30F3\u30D5\u30A9\u30EB\u30C0\u30FC\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0}
|
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\\ \: * ? " < > |
|
||||||
AddContentTagAction.tagExists={0}\u306F\u65E2\u306B{1}\u3068\u30BF\u30B0\u3055\u308C\u3066\u3044\u307E\u3059\u3002\u540C\u3058\u30BF\u30B0\u306F\u4F7F\u7528\u3067\u304D\u307E\u305B\u3093\u3002
|
OpenOutputFolder.CouldNotOpenOutputFolder=\u30a2\u30a6\u30c8\u30d7\u30c3\u30c8\u30d5\u30a9\u30eb\u30c0\u304c\u304c\u958b\u3051\u307e\u305b\u3093\u3067\u3057\u305f
|
||||||
OpenLogFolder.CouldNotOpenLogFolder=\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u30FC\u3092\u958B\u3051\u307E\u305B\u3093\u3067\u3057\u305F
|
|
||||||
CTL_OpenOutputFolder=\u30A2\u30A6\u30C8\u30D7\u30C3\u30C8\u30D5\u30A9\u30EB\u30C0\u3092\u3092\u958B\u304F
|
|
||||||
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
|
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2016 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -20,26 +20,42 @@ package org.sleuthkit.autopsy.actions;
|
|||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.Utilities;
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this Action allow users to delete tags applied to blackboard
|
* Instances of this Action allow users to delete tags applied to blackboard
|
||||||
* artifacts.
|
* artifacts.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"DeleteBlackboardArtifactTagAction.deleteTag=Delete Tag",
|
||||||
|
"# {0} - tagName",
|
||||||
|
"DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
|
||||||
|
"DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error"
|
||||||
|
})
|
||||||
public class DeleteBlackboardArtifactTagAction extends AbstractAction {
|
public class DeleteBlackboardArtifactTagAction extends AbstractAction {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DeleteBlackboardArtifactTagAction.class.getName());
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class,
|
private static final String MENU_TEXT = NbBundle.getMessage(DeleteBlackboardArtifactTagAction.class,
|
||||||
"DeleteBlackboardArtifactTagAction.deleteTags");
|
"DeleteBlackboardArtifactTagAction.deleteTag");
|
||||||
|
|
||||||
// This class is a singleton to support multi-selection of nodes, since
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||||
@ -65,7 +81,7 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
|
|||||||
try {
|
try {
|
||||||
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
|
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
|
Logger.getLogger(DeleteBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
JOptionPane.showMessageDialog(null,
|
JOptionPane.showMessageDialog(null,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
@ -81,28 +97,4 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
|
|||||||
}).start();
|
}).start();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated, use actionPerformed() instead.
|
|
||||||
*
|
|
||||||
* @param event The event associated with the action.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected void doAction(ActionEvent event) {
|
|
||||||
actionPerformed(event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deprecated, does nothing. The TagManager methods to create, update or
|
|
||||||
* delete tags now notify the case that there is a tag change. The case then
|
|
||||||
* publishes an event that triggers a refresh of the tags sub-tree in the
|
|
||||||
* tree view.
|
|
||||||
*
|
|
||||||
* @deprecated
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
protected void refreshDirectoryTree() {
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2015 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -20,25 +20,41 @@ package org.sleuthkit.autopsy.actions;
|
|||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
import javax.swing.SwingUtilities;
|
import javax.swing.SwingUtilities;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.Utilities;
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Instances of this Action allow users to delete tags applied to content.
|
* Instances of this Action allow users to delete tags applied to content.
|
||||||
*/
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"DeleteContentTagAction.deleteTag=Delete Tag",
|
||||||
|
"# {0} - tagName",
|
||||||
|
"DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
|
||||||
|
"DeleteContentTagAction.tagDelErr=Tag Deletion Error"
|
||||||
|
})
|
||||||
public class DeleteContentTagAction extends AbstractAction {
|
public class DeleteContentTagAction extends AbstractAction {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DeleteContentTagAction.class.getName());
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class,
|
private static final String MENU_TEXT = NbBundle.getMessage(DeleteContentTagAction.class,
|
||||||
"DeleteContentTagAction.deleteTags");
|
"DeleteContentTagAction.deleteTag");
|
||||||
|
|
||||||
// This class is a singleton to support multi-selection of nodes, since
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||||
@ -64,7 +80,7 @@ public class DeleteContentTagAction extends AbstractAction {
|
|||||||
try {
|
try {
|
||||||
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
|
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
|
Logger.getLogger(DeleteContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex); //NON-NLS
|
||||||
SwingUtilities.invokeLater(() -> {
|
SwingUtilities.invokeLater(() -> {
|
||||||
JOptionPane.showMessageDialog(null,
|
JOptionPane.showMessageDialog(null,
|
||||||
NbBundle.getMessage(this.getClass(),
|
NbBundle.getMessage(this.getClass(),
|
||||||
|
@ -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.actions;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
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.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to delete tags applied to blackboard
|
||||||
|
* artifacts.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"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;
|
||||||
|
private static final String MENU_TEXT = NbBundle.getMessage(DeleteFileBlackboardArtifactTagAction.class,
|
||||||
|
"DeleteFileBlackboardArtifactTagAction.deleteTag");
|
||||||
|
|
||||||
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
|
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||||
|
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||||
|
private static DeleteFileBlackboardArtifactTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized DeleteFileBlackboardArtifactTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new DeleteFileBlackboardArtifactTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeleteFileBlackboardArtifactTagAction() {
|
||||||
|
super(MENU_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JMenuItem getPopupPresenter() {
|
||||||
|
return new TagMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getActionDisplayName() {
|
||||||
|
return MENU_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"# {0} - artifactID",
|
||||||
|
"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));
|
||||||
|
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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
super.done();
|
||||||
|
try {
|
||||||
|
get();
|
||||||
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while untagging artifact", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class implement a context menu user interface for
|
||||||
|
* creating or selecting a tag name for a tag and specifying an optional tag
|
||||||
|
* comment.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({"# {0} - artifactID",
|
||||||
|
"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();
|
||||||
|
|
||||||
|
// Get the current set of tag names.
|
||||||
|
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||||
|
|
||||||
|
Map<String, TagName> tagNamesMap = null;
|
||||||
|
try {
|
||||||
|
tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each tag name in the current set of tags gets its own menu item in
|
||||||
|
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
|
||||||
|
// a tag with the associated tag name.
|
||||||
|
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
|
||||||
|
try {
|
||||||
|
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 the bookmark tag name only, added shortcut label
|
||||||
|
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
|
||||||
|
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT);
|
||||||
|
}
|
||||||
|
tagNameItem.addActionListener((ActionEvent e) -> {
|
||||||
|
deleteTag(tagName, artifactTag, artifact.getArtifactID());
|
||||||
|
});
|
||||||
|
add(tagNameItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagMenu.class.getName())
|
||||||
|
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getItemCount() == 0) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
199
Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java
Executable file
199
Core/src/org/sleuthkit/autopsy/actions/DeleteFileContentTagAction.java
Executable file
@ -0,0 +1,199 @@
|
|||||||
|
/*
|
||||||
|
* 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.actions;
|
||||||
|
|
||||||
|
import java.awt.event.ActionEvent;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.TreeMap;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
import javafx.scene.control.Alert;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import javax.swing.SwingWorker;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
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.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to delete tags applied to content.
|
||||||
|
*/
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"DeleteFileContentTagAction.deleteTag=Remove File Tag"
|
||||||
|
})
|
||||||
|
public class DeleteFileContentTagAction extends AbstractAction implements Presenter.Popup {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DeleteFileContentTagAction.class.getName());
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
private static final String MENU_TEXT = NbBundle.getMessage(DeleteFileContentTagAction.class,
|
||||||
|
"DeleteFileContentTagAction.deleteTag");
|
||||||
|
|
||||||
|
// This class is a singleton to support multi-selection of nodes, since
|
||||||
|
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||||
|
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||||
|
private static DeleteFileContentTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized DeleteFileContentTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new DeleteFileContentTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeleteFileContentTagAction() {
|
||||||
|
super(MENU_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JMenuItem getPopupPresenter() {
|
||||||
|
return new TagMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
}
|
||||||
|
|
||||||
|
protected String getActionDisplayName() {
|
||||||
|
return MENU_TEXT;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"# {0} - fileID",
|
||||||
|
"DeleteFileContentTagAction.deleteTag.alert=Unable to untag file {0}."})
|
||||||
|
protected void deleteTag(TagName tagName, ContentTag contentTag, long fileId) {
|
||||||
|
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));
|
||||||
|
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.DeleteFileContentTagAction_deleteTag_alert(fileId)).show()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
super.done();
|
||||||
|
try {
|
||||||
|
get();
|
||||||
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while untagging file", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class implement a context menu user interface for
|
||||||
|
* creating or selecting a tag name for a tag and specifying an optional tag
|
||||||
|
* comment.
|
||||||
|
*/
|
||||||
|
private class TagMenu extends JMenu {
|
||||||
|
|
||||||
|
private static final long serialVersionUID = 1L;
|
||||||
|
|
||||||
|
TagMenu() {
|
||||||
|
super(getActionDisplayName());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedAbstractFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
|
||||||
|
if(!selectedAbstractFilesList.isEmpty()) {
|
||||||
|
AbstractFile file = selectedAbstractFilesList.iterator().next();
|
||||||
|
|
||||||
|
// Get the current set of tag names.
|
||||||
|
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||||
|
|
||||||
|
Map<String, TagName> tagNamesMap = null;
|
||||||
|
try {
|
||||||
|
tagNamesMap = new TreeMap<>(tagsManager.getDisplayNamesToTagNamesMap());
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
// Each tag name in the current set of tags gets its own menu item in
|
||||||
|
// the "Quick Tags" sub-menu. Selecting one of these menu items adds
|
||||||
|
// a tag with the associated tag name.
|
||||||
|
if (null != tagNamesMap && !tagNamesMap.isEmpty()) {
|
||||||
|
try {
|
||||||
|
/*List<BlackboardArtifactTag> existingTagsList =
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByArtifact(artifact);*/
|
||||||
|
List<ContentTag> existingTagsList =
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager()
|
||||||
|
.getContentTagsByContent(file);
|
||||||
|
|
||||||
|
for (Map.Entry<String, TagName> entry : tagNamesMap.entrySet()) {
|
||||||
|
String tagDisplayName = entry.getKey();
|
||||||
|
|
||||||
|
TagName tagName = entry.getValue();
|
||||||
|
for(ContentTag contentTag : existingTagsList) {
|
||||||
|
if(tagDisplayName.equals(contentTag.getName().getDisplayName())) {
|
||||||
|
JMenuItem tagNameItem = new JMenuItem(tagDisplayName);
|
||||||
|
// for the bookmark tag name only, added shortcut label
|
||||||
|
if (tagDisplayName.equals(NbBundle.getMessage(AddTagAction.class, "AddBookmarkTagAction.bookmark.text"))) {
|
||||||
|
tagNameItem.setAccelerator(AddBookmarkTagAction.BOOKMARK_SHORTCUT);
|
||||||
|
}
|
||||||
|
tagNameItem.addActionListener((ActionEvent e) -> {
|
||||||
|
deleteTag(tagName, contentTag, file.getId());
|
||||||
|
});
|
||||||
|
add(tagNameItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagMenu.class.getName())
|
||||||
|
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getItemCount() == 0) {
|
||||||
|
setEnabled(false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import javax.annotation.concurrent.GuardedBy;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
|
||||||
@ -61,6 +62,8 @@ class AddImageTask implements Runnable {
|
|||||||
* TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
|
* TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
|
||||||
*/
|
*/
|
||||||
private final Object tskAddImageProcessLock;
|
private final Object tskAddImageProcessLock;
|
||||||
|
|
||||||
|
@GuardedBy("tskAddImageProcessLock")
|
||||||
private boolean tskAddImageProcessStopped;
|
private boolean tskAddImageProcessStopped;
|
||||||
private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
|
private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
|
||||||
|
|
||||||
@ -77,8 +80,9 @@ class AddImageTask implements Runnable {
|
|||||||
* java.util.TimeZone.getID.
|
* java.util.TimeZone.getID.
|
||||||
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
|
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
|
||||||
* FAT filesystem.
|
* FAT filesystem.
|
||||||
* @param imageWriterPath Path that a copy of the image should be written to.
|
* @param imageWriterPath Path that a copy of the image should be
|
||||||
* Use empty string to disable image writing
|
* written to. Use empty string to disable image
|
||||||
|
* writing
|
||||||
* @param progressMonitor Progress monitor to report progress during
|
* @param progressMonitor Progress monitor to report progress during
|
||||||
* processing.
|
* processing.
|
||||||
* @param callback Callback to call when processing is done.
|
* @param callback Callback to call when processing is done.
|
||||||
@ -104,7 +108,7 @@ class AddImageTask implements Runnable {
|
|||||||
progressMonitor.setProgress(0);
|
progressMonitor.setProgress(0);
|
||||||
Case currentCase = Case.getCurrentCase();
|
Case currentCase = Case.getCurrentCase();
|
||||||
String imageWriterPath = "";
|
String imageWriterPath = "";
|
||||||
if(imageWriterSettings != null){
|
if (imageWriterSettings != null) {
|
||||||
imageWriterPath = imageWriterSettings.getPath();
|
imageWriterPath = imageWriterSettings.getPath();
|
||||||
}
|
}
|
||||||
List<String> errorMessages = new ArrayList<>();
|
List<String> errorMessages = new ArrayList<>();
|
||||||
@ -112,8 +116,12 @@ class AddImageTask implements Runnable {
|
|||||||
try {
|
try {
|
||||||
currentCase.getSleuthkitCase().acquireExclusiveLock();
|
currentCase.getSleuthkitCase().acquireExclusiveLock();
|
||||||
synchronized (tskAddImageProcessLock) {
|
synchronized (tskAddImageProcessLock) {
|
||||||
tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true,
|
if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess
|
||||||
ignoreFatOrphanFiles, imageWriterPath);
|
tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true,
|
||||||
|
ignoreFatOrphanFiles, imageWriterPath);
|
||||||
|
} else {
|
||||||
|
return; //we have already cancelled so we do not want to add the image, returning will execute the finally block
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
|
Thread progressUpdateThread = new Thread(new ProgressUpdater(progressMonitor, tskAddImageProcess));
|
||||||
progressUpdateThread.start();
|
progressUpdateThread.start();
|
||||||
@ -142,6 +150,7 @@ class AddImageTask implements Runnable {
|
|||||||
*/
|
*/
|
||||||
public void cancelTask() {
|
public void cancelTask() {
|
||||||
synchronized (tskAddImageProcessLock) {
|
synchronized (tskAddImageProcessLock) {
|
||||||
|
tskAddImageProcessStopped = true;
|
||||||
if (null != tskAddImageProcess) {
|
if (null != tskAddImageProcess) {
|
||||||
try {
|
try {
|
||||||
/*
|
/*
|
||||||
@ -153,7 +162,7 @@ class AddImageTask implements Runnable {
|
|||||||
* called.
|
* called.
|
||||||
*/
|
*/
|
||||||
tskAddImageProcess.stop();
|
tskAddImageProcess.stop();
|
||||||
tskAddImageProcessStopped = true;
|
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS
|
logger.log(Level.SEVERE, String.format("Error cancelling adding image %s to the case database", imagePath), ex); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -213,13 +222,13 @@ class AddImageTask implements Runnable {
|
|||||||
if (!verificationError.isEmpty()) {
|
if (!verificationError.isEmpty()) {
|
||||||
errorMessages.add(verificationError);
|
errorMessages.add(verificationError);
|
||||||
}
|
}
|
||||||
if(imageWriterSettings != null){
|
if (imageWriterSettings != null) {
|
||||||
ImageWriterService.createImageWriter(imageId, imageWriterSettings);
|
ImageWriterService.createImageWriter(imageId, imageWriterSettings);
|
||||||
}
|
}
|
||||||
newDataSources.add(newImage);
|
newDataSources.add(newImage);
|
||||||
} else {
|
} else {
|
||||||
String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
|
String errorMessage = String.format("Error commiting adding image %s to the case database, no object id returned", imagePath); //NON-NLS
|
||||||
logger.log(Level.SEVERE, errorMessage);
|
logger.log(Level.SEVERE, errorMessage);
|
||||||
errorMessages.add(errorMessage);
|
errorMessages.add(errorMessage);
|
||||||
criticalErrorOccurred = true;
|
criticalErrorOccurred = true;
|
||||||
}
|
}
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.casemodule;
|
package org.sleuthkit.autopsy.casemodule;
|
||||||
|
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
|
import java.awt.Cursor;
|
||||||
import java.awt.EventQueue;
|
import java.awt.EventQueue;
|
||||||
import java.awt.Window;
|
import java.awt.Window;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -36,6 +37,7 @@ import org.openide.WizardDescriptor;
|
|||||||
import org.openide.util.HelpCtx;
|
import org.openide.util.HelpCtx;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
|
||||||
@ -319,8 +321,10 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
|
|||||||
cleanupTask = addImageAction.new CleanupTask() {
|
cleanupTask = addImageAction.new CleanupTask() {
|
||||||
@Override
|
@Override
|
||||||
void cleanup() throws Exception {
|
void cleanup() throws Exception {
|
||||||
|
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
|
||||||
cancelDataSourceProcessing(dataSourceId);
|
cancelDataSourceProcessing(dataSourceId);
|
||||||
cancelled = true;
|
cancelled = true;
|
||||||
|
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -148,6 +148,7 @@ GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
|
|||||||
GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd)
|
GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd)
|
||||||
GeneralFilter.executableDesc.text=Executables (*.exe)
|
GeneralFilter.executableDesc.text=Executables (*.exe)
|
||||||
ImageDSProcessor.dsType.text=Disk Image or VM File
|
ImageDSProcessor.dsType.text=Disk Image or VM File
|
||||||
|
GeneralFilter.graphicImageDesc.text=Images (*.png, *.jpg, *.jpeg, *.gif, *.bmp)
|
||||||
ImageDSProcessor.allDesc.text=All Supported Types
|
ImageDSProcessor.allDesc.text=All Supported Types
|
||||||
ImageFilePanel.moduleErr=Module Error
|
ImageFilePanel.moduleErr=Module Error
|
||||||
ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates. See log to determine which module. Some data could be incomplete.
|
ImageFilePanel.moduleErr.msg=A module caused an error listening to ImageFilePanel updates. See log to determine which module. Some data could be incomplete.
|
||||||
|
@ -113,10 +113,8 @@ import org.sleuthkit.datamodel.TskCoreException;
|
|||||||
*/
|
*/
|
||||||
public class Case {
|
public class Case {
|
||||||
|
|
||||||
private static final int NAME_LOCK_TIMOUT_HOURS = 12;
|
private static final int DIR_LOCK_TIMOUT_HOURS = 12;
|
||||||
private static final int SHARED_DIR_LOCK_TIMOUT_HOURS = 12;
|
private static final int RESOURCES_LOCK_TIMOUT_HOURS = 12;
|
||||||
private static final int RESOURCE_LOCK_TIMOUT_HOURS = 12;
|
|
||||||
private static final int MAX_CASEDB_NAME_LEN_MINUS_TIMESTAMP = 47; //Truncate to 63-16=47 chars to accomodate the timestamp
|
|
||||||
private static final String SINGLE_USER_CASE_DB_NAME = "autopsy.db";
|
private static final String SINGLE_USER_CASE_DB_NAME = "autopsy.db";
|
||||||
private static final String EVENT_CHANNEL_NAME = "%s-Case-Events"; //NON-NLS
|
private static final String EVENT_CHANNEL_NAME = "%s-Case-Events"; //NON-NLS
|
||||||
private static final String CACHE_FOLDER = "Cache"; //NON-NLS
|
private static final String CACHE_FOLDER = "Cache"; //NON-NLS
|
||||||
@ -475,18 +473,21 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (null != currentCase) {
|
if (null != currentCase) {
|
||||||
|
String previousCaseDisplayName = currentCase.getDisplayName();
|
||||||
|
String previousCaseName = currentCase.getName();
|
||||||
|
String previousCaseDir = currentCase.getCaseDirectory();
|
||||||
try {
|
try {
|
||||||
closeCurrentCase();
|
closeCurrentCase();
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
logger.log(Level.SEVERE, "Error closing the previous current case", ex); //NON-NLS
|
logger.log(Level.SEVERE, String.format("Error closing the previous current case %s (%s) in %s", previousCaseDisplayName, previousCaseName, previousCaseDir), ex); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(Level.INFO, "Creating current case with display name {0} in {1}", new Object[]{caseDisplayName, caseDir}); //NON-NLS
|
logger.log(Level.INFO, "Creating current case {0} in {1}", new Object[]{caseDisplayName, caseDir}); //NON-NLS
|
||||||
Case newCurrentCase = new Case();
|
Case newCurrentCase = new Case();
|
||||||
newCurrentCase.open(caseDir, caseDisplayName, caseNumber, examiner, caseType);
|
newCurrentCase.create(caseType, caseDir, caseDisplayName, caseNumber, examiner);
|
||||||
currentCase = newCurrentCase;
|
currentCase = newCurrentCase;
|
||||||
logger.log(Level.INFO, "Created currrent case {0} (display name {1}) in {2}", new Object[]{newCurrentCase.getName(), caseDisplayName, caseDir}); //NON-NLS
|
logger.log(Level.INFO, "Created currrent case {0} ({1}) in {2}", new Object[]{newCurrentCase.getDisplayName(), newCurrentCase.getName(), newCurrentCase.getCaseDirectory()}); //NON-NLS
|
||||||
if (RuntimeProperties.runningWithGUI()) {
|
if (RuntimeProperties.runningWithGUI()) {
|
||||||
updateGUIForCaseOpened(newCurrentCase);
|
updateGUIForCaseOpened(newCurrentCase);
|
||||||
}
|
}
|
||||||
@ -723,83 +724,42 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the display name for a case to make a suitable case name for
|
* Transforms a case display name into a unique case name that can be used
|
||||||
* use in case directory paths, coordination service locks, Active MQ
|
* to identify the case even if the display name is changed.
|
||||||
* message channels, etc.
|
|
||||||
*
|
|
||||||
* ActiveMQ:
|
|
||||||
* http://activemq.2283324.n4.nabble.com/What-are-limitations-restrictions-on-destination-name-td4664141.html
|
|
||||||
* may not be ?
|
|
||||||
*
|
*
|
||||||
* @param caseDisplayName A case display name.
|
* @param caseDisplayName A case display name.
|
||||||
*
|
*
|
||||||
* @return The case display name transformed into a corresponding case name.
|
* @return The unique case name.
|
||||||
*
|
|
||||||
* @throws org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException
|
|
||||||
*/
|
*/
|
||||||
public static String displayNameToCaseName(String caseDisplayName) throws IllegalCaseNameException {
|
private static String displayNameToUniqueName(String caseDisplayName) {
|
||||||
|
/*
|
||||||
|
* Replace all non-ASCII characters.
|
||||||
|
*/
|
||||||
|
String uniqueCaseName = caseDisplayName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove all non-ASCII characters.
|
* Replace all control characters.
|
||||||
*/
|
*/
|
||||||
String caseName = caseDisplayName.replaceAll("[^\\p{ASCII}]", "_"); //NON-NLS
|
uniqueCaseName = uniqueCaseName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Remove all control characters.
|
* Replace /, \, :, ?, space, ' ".
|
||||||
*/
|
*/
|
||||||
caseName = caseName.replaceAll("[\\p{Cntrl}]", "_"); //NON-NLS
|
uniqueCaseName = uniqueCaseName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
|
||||||
|
|
||||||
/*
|
|
||||||
* Remove /, \, :, ?, space, ' ".
|
|
||||||
*/
|
|
||||||
caseName = caseName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Make it all lowercase.
|
* Make it all lowercase.
|
||||||
*/
|
*/
|
||||||
caseName = caseName.toLowerCase();
|
uniqueCaseName = uniqueCaseName.toLowerCase();
|
||||||
|
|
||||||
if (caseName.isEmpty()) {
|
|
||||||
throw new IllegalCaseNameException(String.format("Failed to convert case name '%s'", caseDisplayName));
|
|
||||||
}
|
|
||||||
|
|
||||||
return caseName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Transforms a case name into a name for a PostgreSQL database that can be
|
|
||||||
* safely used in SQL commands as described at
|
|
||||||
* http://www.postgresql.org/docs/9.4/static/sql-syntax-lexical.html: 63
|
|
||||||
* chars max, must start with a letter or underscore, following chars can be
|
|
||||||
* letters, underscores, or digits. A timestamp suffix is added to ensure
|
|
||||||
* uniqueness.
|
|
||||||
*
|
|
||||||
* @param caseName The case name.
|
|
||||||
*
|
|
||||||
* @return The case name transformed into a corresponding PostgreSQL case
|
|
||||||
* database name.
|
|
||||||
*/
|
|
||||||
private static String caseNameToCaseDbName(String caseName) throws IllegalCaseNameException {
|
|
||||||
/*
|
|
||||||
* Must start with letter or underscore. If not, prepend an underscore.
|
|
||||||
*/
|
|
||||||
String dbName = caseName;
|
|
||||||
if (dbName.length() > 0 && !(Character.isLetter(dbName.codePointAt(0))) && !(dbName.codePointAt(0) == '_')) {
|
|
||||||
dbName = "_" + dbName;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Truncate to 63-16=47 chars to accomodate the timestamp, then add the
|
* Add a time stamp for uniqueness.
|
||||||
* timestamp.
|
|
||||||
*/
|
*/
|
||||||
if (dbName.length() > MAX_CASEDB_NAME_LEN_MINUS_TIMESTAMP) {
|
|
||||||
dbName = dbName.substring(0, MAX_CASEDB_NAME_LEN_MINUS_TIMESTAMP);
|
|
||||||
}
|
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss");
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
dbName = dbName + "_" + dateFormat.format(date);
|
uniqueCaseName = uniqueCaseName + "_" + dateFormat.format(date);
|
||||||
|
|
||||||
return dbName;
|
return uniqueCaseName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -973,7 +933,7 @@ public class Case {
|
|||||||
private static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir) throws CaseActionException {
|
private static CoordinationService.Lock acquireExclusiveCaseResourcesLock(String caseDir) throws CaseActionException {
|
||||||
try {
|
try {
|
||||||
String resourcesNodeName = caseDir + "_resources";
|
String resourcesNodeName = caseDir + "_resources";
|
||||||
Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, resourcesNodeName, RESOURCE_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
Lock lock = CoordinationService.getInstance().tryGetExclusiveLock(CategoryNode.CASES, resourcesNodeName, RESOURCES_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
||||||
if (null == lock) {
|
if (null == lock) {
|
||||||
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
|
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireResourcesLock());
|
||||||
}
|
}
|
||||||
@ -1585,6 +1545,7 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* @param caseType The type of case (single-user or multi-user).
|
||||||
* @param caseDir The full path of the case directory. The directory
|
* @param caseDir The full path of the case directory. The directory
|
||||||
* will be created if it doesn't already exist; if it
|
* will be created if it doesn't already exist; if it
|
||||||
* exists, it is ASSUMED it was created by calling
|
* exists, it is ASSUMED it was created by calling
|
||||||
@ -1594,7 +1555,6 @@ public class Case {
|
|||||||
* @param caseNumber The case number, can be the empty string.
|
* @param caseNumber The case number, can be the empty string.
|
||||||
* @param examiner The examiner to associate with the case, can be
|
* @param examiner The examiner to associate with the case, can be
|
||||||
* the empty string.
|
* the empty string.
|
||||||
* @param caseType The type of case (single-user or multi-user).
|
|
||||||
*
|
*
|
||||||
* @throws CaseActionException if there is a problem creating the case. The
|
* @throws CaseActionException if there is a problem creating the case. The
|
||||||
* exception will have a user-friendly message
|
* exception will have a user-friendly message
|
||||||
@ -1602,24 +1562,12 @@ public class Case {
|
|||||||
* exception.
|
* exception.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
"Case.exceptionMessage.illegalCaseName=Case name contains illegal characters.",
|
|
||||||
"Case.progressIndicatorTitle.creatingCase=Creating Case",
|
"Case.progressIndicatorTitle.creatingCase=Creating Case",
|
||||||
"Case.progressIndicatorCancelButton.label=Cancel",
|
"Case.progressIndicatorCancelButton.label=Cancel",
|
||||||
"Case.progressMessage.preparing=Preparing...",
|
"Case.progressMessage.preparing=Preparing...",
|
||||||
"Case.progressMessage.openingCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>"
|
"Case.progressMessage.openingCaseResources=<html>Preparing to open case resources.<br>This may take time if another user is upgrading the case.</html>"
|
||||||
})
|
})
|
||||||
private void open(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) throws CaseActionException {
|
private void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) throws CaseActionException {
|
||||||
/*
|
|
||||||
* Clean up the display name for the case to make a suitable immutable
|
|
||||||
* case name.
|
|
||||||
*/
|
|
||||||
String caseName;
|
|
||||||
try {
|
|
||||||
caseName = displayNameToCaseName(caseDisplayName);
|
|
||||||
} catch (IllegalCaseNameException ex) {
|
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(Bundle.Case_exceptionMessage_illegalCaseName()), ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Set up either a GUI progress indicator or a logging progress
|
* Set up either a GUI progress indicator or a logging progress
|
||||||
* indicator.
|
* indicator.
|
||||||
@ -1648,7 +1596,7 @@ public class Case {
|
|||||||
caseLockingExecutor = Executors.newSingleThreadExecutor();
|
caseLockingExecutor = Executors.newSingleThreadExecutor();
|
||||||
Future<Void> future = caseLockingExecutor.submit(() -> {
|
Future<Void> future = caseLockingExecutor.submit(() -> {
|
||||||
if (CaseType.SINGLE_USER_CASE == caseType) {
|
if (CaseType.SINGLE_USER_CASE == caseType) {
|
||||||
open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator);
|
create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
|
||||||
} else {
|
} else {
|
||||||
/*
|
/*
|
||||||
* Acquire a shared case directory lock that will be held as
|
* Acquire a shared case directory lock that will be held as
|
||||||
@ -1657,6 +1605,7 @@ public class Case {
|
|||||||
*/
|
*/
|
||||||
progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
|
progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
|
||||||
acquireSharedCaseDirLock(caseDir);
|
acquireSharedCaseDirLock(caseDir);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Acquire an exclusive case resources lock to ensure only one
|
* Acquire an exclusive case resources lock to ensure only one
|
||||||
* node at a time can create/open/upgrade/close the case
|
* node at a time can create/open/upgrade/close the case
|
||||||
@ -1665,14 +1614,14 @@ public class Case {
|
|||||||
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseDir)) {
|
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseDir)) {
|
||||||
assert (null != resourcesLock);
|
assert (null != resourcesLock);
|
||||||
try {
|
try {
|
||||||
open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator);
|
create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
/*
|
/*
|
||||||
* Release the case directory lock immediately if there
|
* Release the case directory lock immediately if there
|
||||||
* was a problem opening the case.
|
* was a problem opening the case.
|
||||||
*/
|
*/
|
||||||
if (CaseType.MULTI_USER_CASE == caseType) {
|
if (CaseType.MULTI_USER_CASE == caseType) {
|
||||||
releaseSharedCaseDirLock(caseName);
|
releaseSharedCaseDirLock(caseDir);
|
||||||
}
|
}
|
||||||
throw ex;
|
throw ex;
|
||||||
}
|
}
|
||||||
@ -1696,7 +1645,6 @@ public class Case {
|
|||||||
*/
|
*/
|
||||||
try {
|
try {
|
||||||
future.get();
|
future.get();
|
||||||
|
|
||||||
} catch (InterruptedException ex) {
|
} catch (InterruptedException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
|
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), ex);
|
||||||
} catch (ExecutionException ex) {
|
} catch (ExecutionException ex) {
|
||||||
@ -1711,18 +1659,20 @@ public class Case {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates and opens a new case.
|
* Creates a new case.
|
||||||
*
|
*
|
||||||
* @param caseDir The full path of the case directory. The directory
|
* @param caseType The type of case (single-user or multi-user).
|
||||||
* will be created if it doesn't already exist; if it
|
* @param caseDir The full path of the case directory. The
|
||||||
* exists, it is ASSUMED it was created by calling
|
* directory will be created if it doesn't already
|
||||||
* createCaseDirectory.
|
* exist; if it exists, it is ASSUMED it was
|
||||||
* @param caseDisplayName The display name of case, which may be changed
|
* created by calling createCaseDirectory.
|
||||||
* later by the user.
|
* @param caseName The case name.
|
||||||
* @param caseNumber The case number, can be the empty string.
|
* @param caseDisplayName The display name of case, which may be changed
|
||||||
* @param examiner The examiner to associate with the case, can be
|
* later by the user.
|
||||||
* the empty string.
|
* @param caseNumber The case number, can be the empty string.
|
||||||
* @param caseType The type of case (single-user or multi-user).
|
* @param examiner The examiner to associate with the case, can be
|
||||||
|
* the empty string.
|
||||||
|
* @param progressIndicator A progress indicator.
|
||||||
*
|
*
|
||||||
* @throws CaseActionException if there is a problem creating the case. The
|
* @throws CaseActionException if there is a problem creating the case. The
|
||||||
* exception will have a user-friendly message
|
* exception will have a user-friendly message
|
||||||
@ -1730,6 +1680,7 @@ public class Case {
|
|||||||
* exception.
|
* exception.
|
||||||
*/
|
*/
|
||||||
@Messages({
|
@Messages({
|
||||||
|
"Case.exceptionMessage.emptyCaseName=Case name is empty.",
|
||||||
"Case.progressMessage.creatingCaseDirectory=Creating case directory...",
|
"Case.progressMessage.creatingCaseDirectory=Creating case directory...",
|
||||||
"Case.progressMessage.creatingCaseDatabase=Creating case database...",
|
"Case.progressMessage.creatingCaseDatabase=Creating case database...",
|
||||||
"Case.exceptionMessage.couldNotCreateCaseDatabaseName=Failed to create case database name from case name.",
|
"Case.exceptionMessage.couldNotCreateCaseDatabaseName=Failed to create case database name from case name.",
|
||||||
@ -1737,7 +1688,15 @@ public class Case {
|
|||||||
"Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file.",
|
"Case.exceptionMessage.couldNotCreateMetadataFile=Failed to create case metadata file.",
|
||||||
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database."
|
"Case.exceptionMessage.couldNotCreateCaseDatabase=Failed to create case database."
|
||||||
})
|
})
|
||||||
private void open(String caseDir, String caseName, String caseDisplayName, String caseNumber, String examiner, CaseType caseType, ProgressIndicator progressIndicator) throws CaseActionException {
|
private void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner, ProgressIndicator progressIndicator) throws CaseActionException {
|
||||||
|
/*
|
||||||
|
* Create a unique and immutable case name from the case display name.
|
||||||
|
*/
|
||||||
|
if (caseDisplayName.isEmpty()) {
|
||||||
|
throw new CaseActionException(Bundle.Case_exceptionMessage_emptyCaseName());
|
||||||
|
}
|
||||||
|
String caseName = displayNameToUniqueName(caseDisplayName);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Create the case directory, if it does not already exist.
|
* Create the case directory, if it does not already exist.
|
||||||
*
|
*
|
||||||
@ -1768,32 +1727,26 @@ public class Case {
|
|||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase());
|
progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase());
|
||||||
String dbName = null;
|
String dbName = null;
|
||||||
try {
|
|
||||||
if (CaseType.SINGLE_USER_CASE == caseType) {
|
|
||||||
dbName = SINGLE_USER_CASE_DB_NAME;
|
|
||||||
} else if (CaseType.MULTI_USER_CASE == caseType) {
|
|
||||||
dbName = caseNameToCaseDbName(caseName);
|
|
||||||
}
|
|
||||||
} catch (IllegalCaseNameException ex) {
|
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabaseName(), ex);
|
|
||||||
}
|
|
||||||
try {
|
try {
|
||||||
if (CaseType.SINGLE_USER_CASE == caseType) {
|
if (CaseType.SINGLE_USER_CASE == caseType) {
|
||||||
/*
|
/*
|
||||||
* For single-user cases, the case database is a SQLite database
|
* For single-user cases, the case database is a SQLite database
|
||||||
* physically located in the root of the case directory.
|
* with a standard name, physically located in the root of the
|
||||||
|
* case directory.
|
||||||
*/
|
*/
|
||||||
|
dbName = SINGLE_USER_CASE_DB_NAME;
|
||||||
this.caseDb = SleuthkitCase.newCase(Paths.get(caseDir, SINGLE_USER_CASE_DB_NAME).toString());
|
this.caseDb = SleuthkitCase.newCase(Paths.get(caseDir, SINGLE_USER_CASE_DB_NAME).toString());
|
||||||
} else if (CaseType.MULTI_USER_CASE == caseType) {
|
} else if (CaseType.MULTI_USER_CASE == caseType) {
|
||||||
/*
|
/*
|
||||||
* For multi-user cases, the case database is a PostgreSQL
|
* For multi-user cases, the case database is a PostgreSQL
|
||||||
* database physically located on the database server.
|
* database with a name derived from the case display name,
|
||||||
|
* physically located on the database server.
|
||||||
*/
|
*/
|
||||||
this.caseDb = SleuthkitCase.newCase(dbName, UserPreferences.getDatabaseConnectionInfo(), caseDir);
|
this.caseDb = SleuthkitCase.newCase(caseDisplayName, UserPreferences.getDatabaseConnectionInfo(), caseDir);
|
||||||
|
dbName = this.caseDb.getDatabaseName();
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(), ex);
|
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(), ex);
|
||||||
|
|
||||||
} catch (UserPreferencesException ex) {
|
} catch (UserPreferencesException ex) {
|
||||||
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
|
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
|
||||||
}
|
}
|
||||||
@ -1814,7 +1767,7 @@ public class Case {
|
|||||||
/**
|
/**
|
||||||
* Opens an existing case.
|
* Opens an existing case.
|
||||||
*
|
*
|
||||||
* @param caseMetadataFilePath The apth to the case metadata file.
|
* @param caseMetadataFilePath The path to the case metadata file.
|
||||||
*
|
*
|
||||||
* @throws CaseActionException if there is a problem creating the case. The
|
* @throws CaseActionException if there is a problem creating the case. The
|
||||||
* exception will have a user-friendly message
|
* exception will have a user-friendly message
|
||||||
@ -1980,7 +1933,8 @@ public class Case {
|
|||||||
"Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
|
"Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
|
||||||
private void openServices(ProgressIndicator progressIndicator) throws CaseActionException {
|
private void openServices(ProgressIndicator progressIndicator) throws CaseActionException {
|
||||||
/*
|
/*
|
||||||
* Switch to writing to the application logs in the logs subdirectory.
|
* Switch to writing to the application logs in the logs subdirectory of
|
||||||
|
* the case directory.
|
||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_switchingLogDirectory());
|
progressIndicator.progress(Bundle.Case_progressMessage_switchingLogDirectory());
|
||||||
Logger.setLogDirectory(getLogDirectoryPath());
|
Logger.setLogDirectory(getLogDirectoryPath());
|
||||||
@ -1989,12 +1943,11 @@ public class Case {
|
|||||||
* Hook up a SleuthKit layer error reporter.
|
* Hook up a SleuthKit layer error reporter.
|
||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_settingUpTskErrorReporting());
|
progressIndicator.progress(Bundle.Case_progressMessage_settingUpTskErrorReporting());
|
||||||
|
|
||||||
this.sleuthkitErrorReporter = new SleuthkitErrorReporter(MIN_SECS_BETWEEN_TSK_ERROR_REPORTS, NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText"));
|
this.sleuthkitErrorReporter = new SleuthkitErrorReporter(MIN_SECS_BETWEEN_TSK_ERROR_REPORTS, NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText"));
|
||||||
this.caseDb.addErrorObserver(this.sleuthkitErrorReporter);
|
this.caseDb.addErrorObserver(this.sleuthkitErrorReporter);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Clear the temp subdirectory.
|
* Clear the temp subdirectory of the case directory.
|
||||||
*/
|
*/
|
||||||
progressIndicator.progress(Bundle.Case_progressMessage_clearingTempDirectory());
|
progressIndicator.progress(Bundle.Case_progressMessage_clearingTempDirectory());
|
||||||
Case.clearTempSubDir(this.getTempDirectory());
|
Case.clearTempSubDir(this.getTempDirectory());
|
||||||
@ -2335,7 +2288,7 @@ public class Case {
|
|||||||
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
|
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
|
||||||
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
|
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
|
||||||
try {
|
try {
|
||||||
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, SHARED_DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
caseDirLock = CoordinationService.getInstance().tryGetSharedLock(CategoryNode.CASES, caseDir, DIR_LOCK_TIMOUT_HOURS, TimeUnit.HOURS);
|
||||||
if (null == caseDirLock) {
|
if (null == caseDirLock) {
|
||||||
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
|
throw new CaseActionException(Bundle.Case_creationException_couldNotAcquireDirLock());
|
||||||
}
|
}
|
||||||
@ -2400,36 +2353,6 @@ public class Case {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* An exception to throw when a case name with invalid characters is
|
|
||||||
* encountered.
|
|
||||||
*/
|
|
||||||
public final static class IllegalCaseNameException extends Exception {
|
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an exception to throw when a case name with invalid
|
|
||||||
* characters is encountered.
|
|
||||||
*
|
|
||||||
* @param message The exception message.
|
|
||||||
*/
|
|
||||||
IllegalCaseNameException(String message) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Constructs an exception to throw when a case name with invalid
|
|
||||||
* characters is encountered.
|
|
||||||
*
|
|
||||||
* @param message The exception message.
|
|
||||||
* @param cause The exceptin cause.
|
|
||||||
*/
|
|
||||||
IllegalCaseNameException(String message, Throwable cause) {
|
|
||||||
super(message, cause);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new, single-user Autopsy case.
|
* Creates a new, single-user Autopsy case.
|
||||||
*
|
*
|
||||||
|
@ -125,7 +125,7 @@ public final class CaseMetadata {
|
|||||||
* created.
|
* created.
|
||||||
*/
|
*/
|
||||||
CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseDisplayName, String caseNumber, String examiner, String caseDatabase) throws CaseMetadataException {
|
CaseMetadata(String caseDirectory, Case.CaseType caseType, String caseName, String caseDisplayName, String caseNumber, String examiner, String caseDatabase) throws CaseMetadataException {
|
||||||
metadataFilePath = Paths.get(caseDirectory, caseName + FILE_EXTENSION);
|
metadataFilePath = Paths.get(caseDirectory, caseDisplayName + FILE_EXTENSION);
|
||||||
this.caseType = caseType;
|
this.caseType = caseType;
|
||||||
this.caseName = caseName;
|
this.caseName = caseName;
|
||||||
this.caseDisplayName = caseDisplayName;
|
this.caseDisplayName = caseDisplayName;
|
||||||
|
@ -37,14 +37,17 @@ public class GeneralFilter extends FileFilter {
|
|||||||
public static final List<String> ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"}); //NON-NLS
|
public static final List<String> ENCASE_IMAGE_EXTS = Arrays.asList(new String[]{".e01"}); //NON-NLS
|
||||||
public static final String ENCASE_IMAGE_DESC = NbBundle.getMessage(GeneralFilter.class,
|
public static final String ENCASE_IMAGE_DESC = NbBundle.getMessage(GeneralFilter.class,
|
||||||
"GeneralFilter.encaseImageDesc.text");
|
"GeneralFilter.encaseImageDesc.text");
|
||||||
|
|
||||||
public static final List<String> VIRTUAL_MACHINE_EXTS = Arrays.asList(new String[]{".vmdk", ".vhd"}); //NON-NLS
|
public static final List<String> VIRTUAL_MACHINE_EXTS = Arrays.asList(new String[]{".vmdk", ".vhd"}); //NON-NLS
|
||||||
public static final String VIRTUAL_MACHINE_DESC = NbBundle.getMessage(GeneralFilter.class,
|
public static final String VIRTUAL_MACHINE_DESC = NbBundle.getMessage(GeneralFilter.class,
|
||||||
"GeneralFilter.virtualMachineImageDesc.text");
|
"GeneralFilter.virtualMachineImageDesc.text");
|
||||||
|
|
||||||
public static final List<String> EXECUTABLE_EXTS = Arrays.asList(new String[]{".exe"}); //NON-NLS
|
public static final List<String> EXECUTABLE_EXTS = Arrays.asList(new String[]{".exe"}); //NON-NLS
|
||||||
public static final String EXECUTABLE_DESC = NbBundle.getMessage(GeneralFilter.class, "GeneralFilter.executableDesc.text");
|
public static final String EXECUTABLE_DESC = NbBundle.getMessage(GeneralFilter.class, "GeneralFilter.executableDesc.text");
|
||||||
|
|
||||||
|
public static final List<String> GRAPHIC_IMAGE_EXTS = Arrays.asList(new String[]{".png", ".jpeg", ".jpg", ".gif", ".bmp"}); //NON-NLS
|
||||||
|
public static final String GRAPHIC_IMG_DECR = NbBundle.getMessage(GeneralFilter.class, "GeneralFilter.graphicImageDesc.text");
|
||||||
|
|
||||||
private List<String> extensions;
|
private List<String> extensions;
|
||||||
private String desc;
|
private String desc;
|
||||||
|
|
||||||
|
@ -204,25 +204,19 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void validate() throws WizardValidationException {
|
public void validate() throws WizardValidationException {
|
||||||
String caseDisplayName = getComponent().getCaseName();
|
/*
|
||||||
String caseParentDir = getComponent().getCaseParentDir();
|
* Check whether or not the case name is valid. To be valid, the case
|
||||||
|
* name must not contain any characters that are not allowed in file
|
||||||
// check if case Name contain one of this following symbol:
|
* names, since it will be used as the name of the case directory.
|
||||||
// \ / : * ? " < > |
|
*/
|
||||||
if (!Case.isValidName(caseDisplayName)) {
|
String caseName = getComponent().getCaseName();
|
||||||
|
if (!Case.isValidName(caseName)) {
|
||||||
String errorMsg = NbBundle
|
String errorMsg = NbBundle
|
||||||
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
||||||
validationError(errorMsg);
|
validationError(errorMsg);
|
||||||
} else {
|
} else {
|
||||||
String caseName = "";
|
|
||||||
try {
|
|
||||||
caseName = Case.displayNameToCaseName(caseDisplayName);
|
|
||||||
} catch (Case.IllegalCaseNameException ex) {
|
|
||||||
String errorMsg = NbBundle
|
|
||||||
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
|
|
||||||
validationError(errorMsg);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
String caseParentDir = getComponent().getCaseParentDir();
|
||||||
String caseDirPath = caseParentDir + caseName;
|
String caseDirPath = caseParentDir + caseName;
|
||||||
|
|
||||||
// check if the directory exist
|
// check if the directory exist
|
||||||
|
@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.TskData;
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Import a case from single-user to multi-user.
|
* Import a case from single-user to multi-user.
|
||||||
*
|
*
|
||||||
* DO NOT USE, NEEDS TO BE UPDATED
|
* DO NOT USE, NEEDS TO BE UPDATED
|
||||||
*/
|
*/
|
||||||
public class SingleUserCaseConverter {
|
public class SingleUserCaseConverter {
|
||||||
@ -175,9 +175,15 @@ public class SingleUserCaseConverter {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create sanitized names for PostgreSQL and Solr
|
// Create sanitized names for PostgreSQL and Solr
|
||||||
|
/*
|
||||||
|
* RJC: Removed package access sanitizeCaseName method, so this is no
|
||||||
|
* longer correct, but this whole class is currently out-of-date (out of
|
||||||
|
* synch with case database schema) and probably belongs in the TSK
|
||||||
|
* layer anyway, see JIRA-1984.
|
||||||
|
*/
|
||||||
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
|
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMdd_HHmmss"); //NON-NLS
|
||||||
Date date = new Date();
|
Date date = new Date();
|
||||||
String dbName = Case.displayNameToCaseName(icd.getNewCaseName()) + "_" + dateFormat.format(date); //NON-NLS
|
String dbName = icd.getNewCaseName() + "_" + dateFormat.format(date); //NON-NLS
|
||||||
icd.setPostgreSQLDbName(dbName);
|
icd.setPostgreSQLDbName(dbName);
|
||||||
|
|
||||||
// Copy items to new hostname folder structure
|
// Copy items to new hostname folder structure
|
||||||
@ -493,12 +499,12 @@ public class SingleUserCaseConverter {
|
|||||||
if (value > biggestPK) {
|
if (value > biggestPK) {
|
||||||
biggestPK = value;
|
biggestPK = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
// If the entry contains an encoding type, copy it. Otherwise use NONE.
|
// If the entry contains an encoding type, copy it. Otherwise use NONE.
|
||||||
// The test on column count can be removed if we upgrade the database before conversion.
|
// The test on column count can be removed if we upgrade the database before conversion.
|
||||||
int encoding = TskData.EncodingType.NONE.getType();
|
int encoding = TskData.EncodingType.NONE.getType();
|
||||||
ResultSetMetaData rsMetaData = inputResultSet.getMetaData();
|
ResultSetMetaData rsMetaData = inputResultSet.getMetaData();
|
||||||
if(rsMetaData.getColumnCount() == 3){
|
if (rsMetaData.getColumnCount() == 3) {
|
||||||
encoding = inputResultSet.getInt(3);
|
encoding = inputResultSet.getInt(3);
|
||||||
}
|
}
|
||||||
outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS
|
outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS
|
||||||
|
@ -55,15 +55,16 @@ public final class UserPreferences {
|
|||||||
public static final String EXTERNAL_DATABASE_NAME = "ExternalDatabaseName"; //NON-NLS
|
public static final String EXTERNAL_DATABASE_NAME = "ExternalDatabaseName"; //NON-NLS
|
||||||
public static final String EXTERNAL_DATABASE_USER = "ExternalDatabaseUsername"; //NON-NLS
|
public static final String EXTERNAL_DATABASE_USER = "ExternalDatabaseUsername"; //NON-NLS
|
||||||
public static final String EXTERNAL_DATABASE_PASSWORD = "ExternalDatabasePassword"; //NON-NLS
|
public static final String EXTERNAL_DATABASE_PASSWORD = "ExternalDatabasePassword"; //NON-NLS
|
||||||
public static final String EXTERNAL_DATABASE_TYPE = "ExternalDatabaseType"; //NON-NLS
|
public static final String EXTERNAL_DATABASE_TYPE = "ExternalDatabaseType"; //NON-NLS
|
||||||
public static final String INDEXING_SERVER_HOST = "IndexingServerHost"; //NON-NLS
|
public static final String INDEXING_SERVER_HOST = "IndexingServerHost"; //NON-NLS
|
||||||
public static final String INDEXING_SERVER_PORT = "IndexingServerPort"; //NON-NLS
|
public static final String INDEXING_SERVER_PORT = "IndexingServerPort"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_PASSWORD = "MessageServicePassword"; //NON-NLS
|
private static final String MESSAGE_SERVICE_PASSWORD = "MessageServicePassword"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS
|
private static final String MESSAGE_SERVICE_USER = "MessageServiceUser"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
|
private static final String MESSAGE_SERVICE_HOST = "MessageServiceHost"; //NON-NLS
|
||||||
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
|
private static final String MESSAGE_SERVICE_PORT = "MessageServicePort"; //NON-NLS
|
||||||
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
|
public static final String PROCESS_TIME_OUT_ENABLED = "ProcessTimeOutEnabled"; //NON-NLS
|
||||||
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
public static final String PROCESS_TIME_OUT_HOURS = "ProcessTimeOutHours"; //NON-NLS
|
||||||
|
public static final String AGENCY_LOGO_IMAGE_PATH = "AgencyLogoImagePath"; //NON-NLS
|
||||||
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
|
||||||
private static final String DEFAULT_PORT_STRING = "61616";
|
private static final String DEFAULT_PORT_STRING = "61616";
|
||||||
private static final int DEFAULT_PORT_INT = 61616;
|
private static final int DEFAULT_PORT_INT = 61616;
|
||||||
@ -302,7 +303,7 @@ public final class UserPreferences {
|
|||||||
public static void setIsTimeOutEnabled(boolean enabled) {
|
public static void setIsTimeOutEnabled(boolean enabled) {
|
||||||
preferences.putBoolean(PROCESS_TIME_OUT_ENABLED, enabled);
|
preferences.putBoolean(PROCESS_TIME_OUT_ENABLED, enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the display name for this program
|
* Get the display name for this program
|
||||||
* @return Name of this program
|
* @return Name of this program
|
||||||
@ -310,17 +311,17 @@ public final class UserPreferences {
|
|||||||
public static String getAppName(){
|
public static String getAppName(){
|
||||||
return preferences.get(APP_NAME, "Autopsy");
|
return preferences.get(APP_NAME, "Autopsy");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set the display name for this program
|
* Set the display name for this program
|
||||||
*
|
*
|
||||||
* @param name Display name
|
* @param name Display name
|
||||||
*/
|
*/
|
||||||
public static void setAppName(String name){
|
public static void setAppName(String name){
|
||||||
preferences.put(APP_NAME, name);
|
preferences.put(APP_NAME, name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides ability to convert text to hex text.
|
* Provides ability to convert text to hex text.
|
||||||
*/
|
*/
|
||||||
|
@ -46,37 +46,19 @@
|
|||||||
<Layout>
|
<Layout>
|
||||||
<DimensionLayout dim="0">
|
<DimensionLayout dim="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
|
||||||
</Group>
|
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" attributes="0">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="jLabelTimeDisplay" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
|
||||||
</Group>
|
|
||||||
<Component id="jLabelHideKnownFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
|
||||||
<Group type="102" alignment="0" attributes="0">
|
|
||||||
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
|
||||||
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
|
<Component id="keepCurrentViewerRB" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
|
<Component id="useBestViewerRB" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
@ -84,7 +66,26 @@
|
|||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace max="32767" attributes="0"/>
|
<EmptySpace pref="140" max="32767" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Component id="jLabelHideSlackFiles" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="agencyLogoImageLabel" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<EmptySpace min="10" pref="10" max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
|
<Group type="102" attributes="0">
|
||||||
|
<Component id="agencyLogoPathField" min="-2" pref="259" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="browseLogosButton" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<Component id="dataSourcesHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
<Component id="viewsHideSlackCB" alignment="0" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="0" pref="0" max="32767" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
@ -92,7 +93,7 @@
|
|||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
<DimensionLayout dim="1">
|
<DimensionLayout dim="1">
|
||||||
<Group type="103" groupAlignment="0" attributes="0">
|
<Group type="103" groupAlignment="0" attributes="0">
|
||||||
<Group type="102" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
@ -117,7 +118,14 @@
|
|||||||
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace max="-2" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
<Component id="useGMTTimeRB" min="-2" max="-2" attributes="0"/>
|
<Component id="useGMTTimeRB" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace pref="148" max="32767" attributes="0"/>
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Component id="agencyLogoImageLabel" min="-2" max="-2" attributes="0"/>
|
||||||
|
<EmptySpace max="-2" attributes="0"/>
|
||||||
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
<Component id="agencyLogoPathField" alignment="3" max="32767" attributes="0"/>
|
||||||
|
<Component id="browseLogosButton" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
|
</Group>
|
||||||
|
<EmptySpace min="-2" pref="35" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
</Group>
|
</Group>
|
||||||
</DimensionLayout>
|
</DimensionLayout>
|
||||||
@ -249,6 +257,36 @@
|
|||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
|
<Component class="javax.swing.JLabel" name="agencyLogoImageLabel">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoImageLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JTextField" name="agencyLogoPathField">
|
||||||
|
<Properties>
|
||||||
|
<Property name="editable" type="boolean" value="false"/>
|
||||||
|
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
|
||||||
|
<Color blue="ff" green="ff" red="ff" type="rgb"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoPathField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
<Property name="focusable" type="boolean" value="false"/>
|
||||||
|
<Property name="requestFocusEnabled" type="boolean" value="false"/>
|
||||||
|
</Properties>
|
||||||
|
</Component>
|
||||||
|
<Component class="javax.swing.JButton" name="browseLogosButton">
|
||||||
|
<Properties>
|
||||||
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
|
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.browseLogosButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
|
</Property>
|
||||||
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseLogosButtonActionPerformed"/>
|
||||||
|
</Events>
|
||||||
|
</Component>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
</Container>
|
</Container>
|
||||||
</SubComponents>
|
</SubComponents>
|
||||||
|
@ -18,8 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.corecomponents;
|
package org.sleuthkit.autopsy.corecomponents;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
import javax.swing.JFileChooser;
|
||||||
import org.netbeans.spi.options.OptionsPanelController;
|
import org.netbeans.spi.options.OptionsPanelController;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
import org.sleuthkit.autopsy.report.ReportBranding;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Options panel that allow users to set application preferences.
|
* Options panel that allow users to set application preferences.
|
||||||
@ -27,9 +32,14 @@ import org.sleuthkit.autopsy.core.UserPreferences;
|
|||||||
final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
||||||
|
|
||||||
private static final long serialVersionUID = 1L;
|
private static final long serialVersionUID = 1L;
|
||||||
|
private final JFileChooser fc;
|
||||||
|
|
||||||
AutopsyOptionsPanel() {
|
AutopsyOptionsPanel() {
|
||||||
initComponents();
|
initComponents();
|
||||||
|
fc = new JFileChooser();
|
||||||
|
fc.setFileSelectionMode(JFileChooser.FILES_ONLY);
|
||||||
|
fc.setMultiSelectionEnabled(false);
|
||||||
|
fc.setFileFilter(new GeneralFilter(GeneralFilter.GRAPHIC_IMAGE_EXTS, GeneralFilter.GRAPHIC_IMG_DECR));
|
||||||
}
|
}
|
||||||
|
|
||||||
void load() {
|
void load() {
|
||||||
@ -43,6 +53,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
|
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
|
||||||
useLocalTimeRB.setSelected(useLocalTime);
|
useLocalTimeRB.setSelected(useLocalTime);
|
||||||
useGMTTimeRB.setSelected(!useLocalTime);
|
useGMTTimeRB.setSelected(!useLocalTime);
|
||||||
|
agencyLogoPathField.setText(ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP));
|
||||||
}
|
}
|
||||||
|
|
||||||
void store() {
|
void store() {
|
||||||
@ -52,6 +63,12 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
|
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
|
||||||
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
|
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.isSelected());
|
||||||
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
|
UserPreferences.setDisplayTimesInLocalTime(useLocalTimeRB.isSelected());
|
||||||
|
if (!agencyLogoPathField.getText().isEmpty()) {
|
||||||
|
File image = new File(agencyLogoPathField.getText());
|
||||||
|
if (image.exists()) {
|
||||||
|
ModuleSettings.setConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP, agencyLogoPathField.getText());
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
boolean valid() {
|
boolean valid() {
|
||||||
@ -82,6 +99,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
dataSourcesHideSlackCB = new javax.swing.JCheckBox();
|
dataSourcesHideSlackCB = new javax.swing.JCheckBox();
|
||||||
viewsHideSlackCB = new javax.swing.JCheckBox();
|
viewsHideSlackCB = new javax.swing.JCheckBox();
|
||||||
jLabelHideSlackFiles = new javax.swing.JLabel();
|
jLabelHideSlackFiles = new javax.swing.JLabel();
|
||||||
|
agencyLogoImageLabel = new javax.swing.JLabel();
|
||||||
|
agencyLogoPathField = new javax.swing.JTextField();
|
||||||
|
browseLogosButton = new javax.swing.JButton();
|
||||||
|
|
||||||
jScrollPane1.setBorder(null);
|
jScrollPane1.setBorder(null);
|
||||||
|
|
||||||
@ -155,6 +175,21 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(jLabelHideSlackFiles, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.jLabelHideSlackFiles.text")); // NOI18N
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
|
||||||
|
|
||||||
|
agencyLogoPathField.setEditable(false);
|
||||||
|
agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
|
||||||
|
agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
|
||||||
|
agencyLogoPathField.setFocusable(false);
|
||||||
|
agencyLogoPathField.setRequestFocusEnabled(false);
|
||||||
|
|
||||||
|
org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
|
||||||
|
browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
browseLogosButtonActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
|
||||||
jPanel1.setLayout(jPanel1Layout);
|
jPanel1.setLayout(jPanel1Layout);
|
||||||
jPanel1Layout.setHorizontalGroup(
|
jPanel1Layout.setHorizontalGroup(
|
||||||
@ -162,33 +197,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addContainerGap()
|
.addContainerGap()
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.TRAILING, jPanel1Layout.createSequentialGroup()
|
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(jLabelTimeDisplay)
|
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
|
||||||
.addGap(10, 10, 10)
|
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
|
||||||
.addComponent(useLocalTimeRB)
|
|
||||||
.addComponent(useGMTTimeRB))))
|
|
||||||
.addContainerGap(512, Short.MAX_VALUE))
|
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(jLabelTimeDisplay)
|
||||||
.addComponent(jLabelHideKnownFiles)
|
.addComponent(jLabelHideKnownFiles)
|
||||||
.addComponent(jLabelSelectFile)
|
.addComponent(jLabelSelectFile)
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addGap(10, 10, 10)
|
.addGap(10, 10, 10)
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addComponent(useLocalTimeRB)
|
||||||
|
.addComponent(useGMTTimeRB)
|
||||||
.addComponent(keepCurrentViewerRB)
|
.addComponent(keepCurrentViewerRB)
|
||||||
.addComponent(useBestViewerRB)
|
.addComponent(useBestViewerRB)
|
||||||
.addComponent(dataSourcesHideKnownCB)
|
.addComponent(dataSourcesHideKnownCB)
|
||||||
.addComponent(viewsHideKnownCB))))
|
.addComponent(viewsHideKnownCB))))
|
||||||
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
|
.addContainerGap(140, Short.MAX_VALUE))
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
.addComponent(jLabelHideSlackFiles)
|
.addComponent(jLabelHideSlackFiles)
|
||||||
|
.addComponent(agencyLogoImageLabel)
|
||||||
.addGroup(jPanel1Layout.createSequentialGroup()
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
.addGap(10, 10, 10)
|
.addGap(10, 10, 10)
|
||||||
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
|
||||||
|
.addGroup(jPanel1Layout.createSequentialGroup()
|
||||||
|
.addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(browseLogosButton))
|
||||||
.addComponent(dataSourcesHideSlackCB)
|
.addComponent(dataSourcesHideSlackCB)
|
||||||
.addComponent(viewsHideSlackCB))))
|
.addComponent(viewsHideSlackCB))))
|
||||||
.addGap(0, 0, Short.MAX_VALUE))))
|
.addGap(0, 0, Short.MAX_VALUE))))
|
||||||
@ -220,7 +254,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
.addComponent(useLocalTimeRB)
|
.addComponent(useLocalTimeRB)
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
.addComponent(useGMTTimeRB)
|
.addComponent(useGMTTimeRB)
|
||||||
.addContainerGap(148, Short.MAX_VALUE))
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addComponent(agencyLogoImageLabel)
|
||||||
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
|
||||||
|
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
|
.addComponent(agencyLogoPathField)
|
||||||
|
.addComponent(browseLogosButton))
|
||||||
|
.addGap(35, 35, 35))
|
||||||
);
|
);
|
||||||
|
|
||||||
jScrollPane1.setViewportView(jPanel1);
|
jScrollPane1.setViewportView(jPanel1);
|
||||||
@ -269,7 +309,19 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
|
|||||||
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
|
}//GEN-LAST:event_viewsHideSlackCBActionPerformed
|
||||||
|
|
||||||
|
private void browseLogosButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_browseLogosButtonActionPerformed
|
||||||
|
int returnState = fc.showOpenDialog(this);
|
||||||
|
if (returnState == JFileChooser.APPROVE_OPTION) {
|
||||||
|
String path = fc.getSelectedFile().getPath();
|
||||||
|
agencyLogoPathField.setText(path);
|
||||||
|
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
|
||||||
|
}
|
||||||
|
}//GEN-LAST:event_browseLogosButtonActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
|
private javax.swing.JLabel agencyLogoImageLabel;
|
||||||
|
private javax.swing.JTextField agencyLogoPathField;
|
||||||
|
private javax.swing.JButton browseLogosButton;
|
||||||
private javax.swing.ButtonGroup buttonGroup1;
|
private javax.swing.ButtonGroup buttonGroup1;
|
||||||
private javax.swing.ButtonGroup buttonGroup3;
|
private javax.swing.ButtonGroup buttonGroup3;
|
||||||
private javax.swing.JCheckBox dataSourcesHideKnownCB;
|
private javax.swing.JCheckBox dataSourcesHideKnownCB;
|
||||||
|
@ -194,3 +194,7 @@ MultiUserSettingsPanel.InvalidPortNumber=Invalid port number
|
|||||||
AutopsyOptionsPanel.jLabelHideSlackFiles.text=Hide slack files in the:
|
AutopsyOptionsPanel.jLabelHideSlackFiles.text=Hide slack files in the:
|
||||||
AutopsyOptionsPanel.dataSourcesHideSlackCB.text=Data Sources area (the directory hierarchy)
|
AutopsyOptionsPanel.dataSourcesHideSlackCB.text=Data Sources area (the directory hierarchy)
|
||||||
AutopsyOptionsPanel.viewsHideSlackCB.text=Views area
|
AutopsyOptionsPanel.viewsHideSlackCB.text=Views area
|
||||||
|
AutopsyOptionsPanel.agencyLogoImageLabel.toolTipText=
|
||||||
|
AutopsyOptionsPanel.agencyLogoImageLabel.text=Image to use as the agency logo for HTML reports:
|
||||||
|
AutopsyOptionsPanel.browseLogosButton.text=Browse
|
||||||
|
AutopsyOptionsPanel.agencyLogoPathField.text=
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,18 +19,25 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
@ -64,129 +71,227 @@ public class DataModelActionsFactory {
|
|||||||
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
|
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
|
||||||
|
|
||||||
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
public static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
||||||
final FileNode fileNode = new FileNode(file);
|
final FileNode fileNode = new FileNode(file);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
|
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(SlackFile slackFile, boolean isArtifactSource) {
|
public static List<Action> getActions(SlackFile slackFile, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
|
||||||
final SlackFileNode slackFileNode = new SlackFileNode(slackFile);
|
final SlackFileNode slackFileNode = new SlackFileNode(slackFile);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
|
public static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
||||||
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
|
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());//
|
actionsList.add(ExtractAction.getInstance());//
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(Directory directory, boolean isArtifactSource) {
|
public static List<Action> getActions(Directory directory, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
|
||||||
DirectoryNode directoryNode = new DirectoryNode(directory);
|
DirectoryNode directoryNode = new DirectoryNode(directory);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(VirtualDirectory directory, boolean isArtifactSource) {
|
public static List<Action> getActions(VirtualDirectory directory, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
|
||||||
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
|
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(LocalFile file, boolean isArtifactSource) {
|
public static List<Action> getActions(LocalFile file, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
||||||
final LocalFileNode localFileNode = new LocalFileNode(file);
|
final LocalFileNode localFileNode = new LocalFileNode(file);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(DerivedFile file, boolean isArtifactSource) {
|
public static List<Action> getActions(DerivedFile file, boolean isArtifactSource) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
|
||||||
final LocalFileNode localFileNode = new LocalFileNode(file);
|
final LocalFileNode localFileNode = new LocalFileNode(file);
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
|
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
|
||||||
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
|
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
if (isArtifactSource) {
|
if (isArtifactSource) {
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
if(isArtifactSource) {
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<Action> getActions(Content content, boolean isArtifactSource) {
|
public static List<Action> getActions(Content content, boolean isArtifactSource) {
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,11 +19,16 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
@ -37,6 +42,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
|||||||
* are more directories.
|
* are more directories.
|
||||||
*/
|
*/
|
||||||
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DirectoryNode.class.getName());
|
||||||
|
|
||||||
public static final String DOTDOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.parFolder.text");
|
public static final String DOTDOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.parFolder.text");
|
||||||
public static final String DOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.curFolder.text");
|
public static final String DOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.curFolder.text");
|
||||||
@ -71,23 +78,29 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
*/
|
*/
|
||||||
@Override
|
@Override
|
||||||
public Action[] getActions(boolean popup) {
|
public Action[] getActions(boolean popup) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
for (Action a : super.getActions(true)) {
|
for (Action a : super.getActions(true)) {
|
||||||
actions.add(a);
|
actionsList.add(a);
|
||||||
}
|
}
|
||||||
if (!getDirectoryBrowseMode()) {
|
if (!getDirectoryBrowseMode()) {
|
||||||
actions.add(new ViewContextAction(
|
actionsList.add(new ViewContextAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DirectoryNode.getActions.viewFileInDir.text"), this));
|
NbBundle.getMessage(this.getClass(), "DirectoryNode.getActions.viewFileInDir.text"), this));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
}
|
}
|
||||||
actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this));
|
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this));
|
||||||
actions.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
|
actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions.toArray(new Action[actions.size()]);
|
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2016 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,13 +19,18 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
import org.sleuthkit.autopsy.coreutils.ImageUtils;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
@ -41,6 +46,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
|
|||||||
* children.
|
* children.
|
||||||
*/
|
*/
|
||||||
public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(FileNode.class.getName());
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Constructor
|
* Constructor
|
||||||
@ -96,6 +103,12 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
|
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[actionsList.size()]);
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2014 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,17 +19,22 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -121,6 +126,13 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2016 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -20,14 +20,19 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
@ -39,6 +44,8 @@ import org.sleuthkit.datamodel.AbstractFile;
|
|||||||
* A Node for a LocalFile or DerivedFile content object.
|
* A Node for a LocalFile or DerivedFile content object.
|
||||||
*/
|
*/
|
||||||
public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(LocalFileNode.class.getName());
|
||||||
|
|
||||||
public LocalFileNode(AbstractFile af) {
|
public LocalFileNode(AbstractFile af) {
|
||||||
super(af);
|
super(af);
|
||||||
@ -98,6 +105,13 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
|
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2016 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,10 +19,14 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
@ -84,6 +88,13 @@ public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[actionsList.size()]);
|
return actionsList.toArray(new Action[actionsList.size()]);
|
||||||
}
|
}
|
||||||
|
@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.directorytree;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyVetoException;
|
import java.beans.PropertyVetoException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.prefs.PreferenceChangeEvent;
|
import java.util.prefs.PreferenceChangeEvent;
|
||||||
@ -33,8 +35,11 @@ import org.openide.nodes.FilterNode;
|
|||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileBlackboardArtifactTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.core.UserPreferences;
|
import org.sleuthkit.autopsy.core.UserPreferences;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
@ -70,6 +75,8 @@ import org.sleuthkit.datamodel.VirtualDirectory;
|
|||||||
* defines the actions that the node should have.
|
* defines the actions that the node should have.
|
||||||
*/
|
*/
|
||||||
public class DataResultFilterNode extends FilterNode {
|
public class DataResultFilterNode extends FilterNode {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DataResultFilterNode.class.getName());
|
||||||
|
|
||||||
private static boolean filterKnownFromDataSources = UserPreferences.hideKnownFilesInDataSourcesTree();
|
private static boolean filterKnownFromDataSources = UserPreferences.hideKnownFilesInDataSourcesTree();
|
||||||
private static boolean filterKnownFromViews = UserPreferences.hideKnownFilesInViewsTree();
|
private static boolean filterKnownFromViews = UserPreferences.hideKnownFilesInViewsTree();
|
||||||
@ -260,29 +267,29 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
|
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
|
||||||
// TODO UPDATE: There is now a DataModelActionsFactory utility;
|
// TODO UPDATE: There is now a DataModelActionsFactory utility;
|
||||||
|
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
|
||||||
//merge predefined specific node actions if bban subclasses have their own
|
//merge predefined specific node actions if bban subclasses have their own
|
||||||
for (Action a : ban.getActions(true)) {
|
for (Action a : ban.getActions(true)) {
|
||||||
actions.add(a);
|
actionsList.add(a);
|
||||||
}
|
}
|
||||||
BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class);
|
BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class);
|
||||||
final int artifactTypeID = ba.getArtifactTypeID();
|
final int artifactTypeID = ba.getArtifactTypeID();
|
||||||
|
|
||||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|
||||||
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
||||||
actions.add(new ViewContextAction(
|
actionsList.add(new ViewContextAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), ban));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), ban));
|
||||||
} else {
|
} else {
|
||||||
// if the artifact links to another file, add an action to go to
|
// if the artifact links to another file, add an action to go to
|
||||||
// that file
|
// that file
|
||||||
Content c = findLinked(ban);
|
Content c = findLinked(ban);
|
||||||
if (c != null) {
|
if (c != null) {
|
||||||
actions.add(new ViewContextAction(
|
actionsList.add(new ViewContextAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
|
||||||
}
|
}
|
||||||
// action to go to the source file of the artifact
|
// action to go to the source file of the artifact
|
||||||
actions.add(new ViewContextAction(
|
actionsList.add(new ViewContextAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewSrcFileInDir.text"), ban));
|
||||||
}
|
}
|
||||||
Content c = ban.getLookup().lookup(File.class);
|
Content c = ban.getLookup().lookup(File.class);
|
||||||
@ -304,28 +311,44 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
n = new SlackFileNode((SlackFile) c);
|
n = new SlackFileNode((SlackFile) c);
|
||||||
}
|
}
|
||||||
if (n != null) {
|
if (n != null) {
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(new NewWindowViewAction(
|
actionsList.add(new NewWindowViewAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewInNewWin.text"), n));
|
||||||
actions.add(new ExternalViewerAction(
|
actionsList.add(new ExternalViewerAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.openInExtViewer.text"), n));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
if (md5Action) {
|
if (md5Action) {
|
||||||
actions.add(new HashSearchAction(
|
actionsList.add(new HashSearchAction(
|
||||||
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
|
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
|
||||||
}
|
}
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
// There's no specific file associated with the artifact, but
|
// There's no specific file associated with the artifact, but
|
||||||
// we can still tag the artifact itself
|
// we can still tag the artifact itself
|
||||||
actions.add(null);
|
actionsList.add(null);
|
||||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
}
|
}
|
||||||
return actions;
|
|
||||||
|
final Collection<BlackboardArtifact> selectedArtifactsList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class));
|
||||||
|
if(selectedArtifactsList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
if(n != null) {
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
}
|
||||||
|
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2014 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -19,13 +19,18 @@
|
|||||||
package org.sleuthkit.autopsy.directorytree;
|
package org.sleuthkit.autopsy.directorytree;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.Collections;
|
import java.util.Collections;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentVisitor;
|
import org.sleuthkit.datamodel.ContentVisitor;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
@ -85,48 +90,82 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final Directory d) {
|
public List<? extends Action> visit(final Directory d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
if (!d.isDataSource()) {
|
if (!d.isDataSource()) {
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final DerivedFile d) {
|
public List<? extends Action> visit(final DerivedFile d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final LocalFile d) {
|
public List<? extends Action> visit(final LocalFile d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -31,7 +31,6 @@ import org.openide.util.NbBundle;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.examples.SampleExecutableIngestModuleFactory;
|
import org.sleuthkit.autopsy.examples.SampleExecutableIngestModuleFactory;
|
||||||
import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory;
|
import org.sleuthkit.autopsy.examples.SampleIngestModuleFactory;
|
||||||
import org.sleuthkit.autopsy.modules.android.AndroidModuleFactory;
|
|
||||||
import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory;
|
import org.sleuthkit.autopsy.modules.e01verify.E01VerifierModuleFactory;
|
||||||
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
|
import org.sleuthkit.autopsy.modules.exif.ExifParserModuleFactory;
|
||||||
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
|
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
|
||||||
@ -63,7 +62,6 @@ final class IngestModuleFactoryLoader {
|
|||||||
add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS
|
add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS
|
||||||
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
|
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
|
||||||
add(E01VerifierModuleFactory.class.getCanonicalName());
|
add(E01VerifierModuleFactory.class.getCanonicalName());
|
||||||
add(AndroidModuleFactory.class.getCanonicalName());
|
|
||||||
add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
|
add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
|
||||||
add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName());
|
add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName());
|
||||||
}
|
}
|
||||||
|
@ -1,148 +0,0 @@
|
|||||||
/*
|
|
||||||
* 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.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
package org.sleuthkit.autopsy.modules.android;
|
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModule;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestMessage;
|
|
||||||
|
|
||||||
class AndroidIngestModule implements DataSourceIngestModule {
|
|
||||||
|
|
||||||
private IngestJobContext context = null;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void startUp(IngestJobContext context) throws IngestModuleException {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public ProcessResult process(Content dataSource, DataSourceIngestModuleProgress progressBar) {
|
|
||||||
ArrayList<String> errors = new ArrayList<>();
|
|
||||||
progressBar.switchToDeterminate(9);
|
|
||||||
FileManager fileManager = Case.getCurrentCase().getServices().getFileManager();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ContactAnalyzer.findContacts(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(1);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Contacts"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
CallLogAnalyzer.findCallLogs(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(2);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Call Logs"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
TextMessageAnalyzer.findTexts(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(3);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Text Messages"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
TangoMessageAnalyzer.findTangoMessages(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(4);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Tango Messages"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
WWFMessageAnalyzer.findWWFMessages(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(5);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Words with Friends Messages"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
GoogleMapLocationAnalyzer.findGeoLocations(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(6);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Google Map Locations"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
BrowserLocationAnalyzer.findGeoLocations(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(7);
|
|
||||||
if (context.dataSourceIngestIsCancelled()) {
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Browser Locations"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
CacheLocationAnalyzer.findGeoLocations(dataSource, fileManager, context);
|
|
||||||
progressBar.progress(8);
|
|
||||||
} catch (Exception e) {
|
|
||||||
errors.add("Error getting Cache Locations"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
// create the final message for inbox
|
|
||||||
StringBuilder errorMessage = new StringBuilder();
|
|
||||||
String errorMsgSubject;
|
|
||||||
IngestMessage.MessageType msgLevel = IngestMessage.MessageType.INFO;
|
|
||||||
if (errors.isEmpty() == false) {
|
|
||||||
msgLevel = IngestMessage.MessageType.ERROR;
|
|
||||||
errorMessage.append("Errors were encountered"); //NON-NLS
|
|
||||||
for (String msg : errors) {
|
|
||||||
errorMessage.append("<li>").append(msg).append("</li>\n"); //NON-NLS
|
|
||||||
}
|
|
||||||
errorMessage.append("</ul>\n"); //NON-NLS
|
|
||||||
|
|
||||||
if (errors.size() == 1) {
|
|
||||||
errorMsgSubject = "One error was found"; //NON-NLS
|
|
||||||
} else {
|
|
||||||
errorMsgSubject = "errors found: " + errors.size(); //NON-NLS
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
errorMessage.append("No errors"); //NON-NLS
|
|
||||||
errorMsgSubject = "No errors"; //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
return IngestModule.ProcessResult.OK;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Version;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleFactory;
|
|
||||||
import org.sleuthkit.autopsy.ingest.DataSourceIngestModule;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleFactoryAdapter;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestModuleIngestJobSettings;
|
|
||||||
|
|
||||||
@ServiceProvider(service = IngestModuleFactory.class) //
|
|
||||||
public class AndroidModuleFactory extends IngestModuleFactoryAdapter {
|
|
||||||
|
|
||||||
static String getModuleName() {
|
|
||||||
return NbBundle.getMessage(AndroidModuleFactory.class, "AndroidModuleFactory.moduleName");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModuleDisplayName() {
|
|
||||||
return getModuleName();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModuleDescription() {
|
|
||||||
return NbBundle.getMessage(AndroidModuleFactory.class, "AndroidModuleFactory.moduleDescription");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getModuleVersionNumber() {
|
|
||||||
return Version.getVersion();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isDataSourceIngestModuleFactory() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DataSourceIngestModule createDataSourceIngestModule(IngestModuleIngestJobSettings settings) {
|
|
||||||
return new AndroidIngestModule();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
@ -1,135 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Analyzes database created by browser that stores GEO location info.
|
|
||||||
*/
|
|
||||||
class BrowserLocationAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(BrowserLocationAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
public static void findGeoLocations(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
List<AbstractFile> abstractFiles = fileManager.findFiles(dataSource, "CachedGeoposition%.db"); //NON-NLS
|
|
||||||
|
|
||||||
for (AbstractFile abstractFile : abstractFiles) {
|
|
||||||
try {
|
|
||||||
if (abstractFile.getSize() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
findGeoLocationsInDB(jFile.toString(), abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Browser Location files", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding Browser Location files", e); //NON-NLS
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@NbBundle.Messages({"BrowserLocationAnalyzer.indexError.message=Failed to index GPS trackpoint artifact for keyword search."})
|
|
||||||
private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error connecting to sql database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT timestamp, latitude, longitude, accuracy FROM CachedPosition;"); //NON-NLS
|
|
||||||
|
|
||||||
while (resultSet.next()) {
|
|
||||||
Long timestamp = Long.valueOf(resultSet.getString("timestamp")) / 1000; //NON-NLS
|
|
||||||
double latitude = Double.valueOf(resultSet.getString("latitude")); //NON-NLS
|
|
||||||
double longitude = Double.valueOf(resultSet.getString("longitude")); //NON-NLS
|
|
||||||
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, moduleName, latitude));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, moduleName, longitude));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, timestamp));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName,
|
|
||||||
NbBundle.getMessage(BrowserLocationAnalyzer.class,
|
|
||||||
"BrowserLocationAnalyzer.bbAttribute.browserLocationHistory")));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy));
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactTypeName(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.BrowserLocationAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error Putting artifacts to Blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +0,0 @@
|
|||||||
AndroidModuleFactory.moduleName=Android Analyzer
|
|
||||||
AndroidModuleFactory.moduleDescription=Extracts Android system and third-party app data.
|
|
||||||
BrowserLocationAnalyzer.bbAttribute.browserLocationHistory=Browser Location History
|
|
||||||
CacheLocationAnalyzer.bbAttribute.fileLocationHistory={0} Location History
|
|
||||||
GoogleMapLocationAnalyzer.bbAttribute.destination=Destination
|
|
||||||
GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory=Google Maps History
|
|
||||||
TangoMessageAnalyzer.bbAttribute.tangoMessage=Tango Message
|
|
||||||
TextMessageAnalyzer.bbAttribute.incoming=Incoming
|
|
||||||
TextMessageAnalyzer.bbAttribute.outgoing=Outgoing
|
|
||||||
TextMessageAnalyzer.bbAttribute.smsMessage=SMS Message
|
|
||||||
WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg=Words With Friends Message
|
|
@ -1,10 +0,0 @@
|
|||||||
AndroidModuleFactory.moduleDescription=Android\u30b7\u30b9\u30c6\u30e0\u304a\u3088\u3073\u7b2c\u4e09\u8005\u30a2\u30d7\u30ea\u30c7\u30fc\u30bf\u3092\u62bd\u51fa
|
|
||||||
BrowserLocationAnalyzer.bbAttribute.browserLocationHistory=\u30d6\u30e9\u30a6\u30b6\u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u5c65\u6b74
|
|
||||||
CacheLocationAnalyzer.bbAttribute.fileLocationHistory={0} \u30ed\u30b1\u30fc\u30b7\u30e7\u30f3\u5c65\u6b74
|
|
||||||
GoogleMapLocationAnalyzer.bbAttribute.destination=\u76ee\u7684\u5730
|
|
||||||
GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory=Google\u30de\u30c3\u30d7\u5c65\u6b74
|
|
||||||
TangoMessageAnalyzer.bbAttribute.tangoMessage=Tango\u30e1\u30c3\u30bb\u30fc\u30b8
|
|
||||||
TextMessageAnalyzer.bbAttribute.incoming=\u53d7\u4fe1
|
|
||||||
TextMessageAnalyzer.bbAttribute.outgoing=\u9001\u4fe1
|
|
||||||
TextMessageAnalyzer.bbAttribute.smsMessage=SMS\u30e1\u30c3\u30bb\u30fc\u30b8
|
|
||||||
WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg=Words With Friends\u30e1\u30c3\u30bb\u30fc\u30b8
|
|
@ -1,163 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.InputStream;
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.nio.ByteBuffer;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Parses cache files that Android maintains for Wifi and cell towers. Adds GPS
|
|
||||||
* points to blackboard.
|
|
||||||
*/
|
|
||||||
class CacheLocationAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(CacheLocationAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* cache.cell stores mobile tower GPS locations and cache.wifi stores GPS
|
|
||||||
* and MAC info from Wifi points.
|
|
||||||
*/
|
|
||||||
public static void findGeoLocations(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
List<AbstractFile> abstractFiles = fileManager.findFiles(dataSource, "cache.cell"); //NON-NLS
|
|
||||||
abstractFiles.addAll(fileManager.findFiles(dataSource, "cache.wifi")); //NON-NLS
|
|
||||||
|
|
||||||
for (AbstractFile abstractFile : abstractFiles) {
|
|
||||||
try {
|
|
||||||
if (abstractFile.getSize() == 0) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
|
|
||||||
findGeoLocationsInFile(jFile, abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing cached Location files", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding cached Location files", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"CacheLocationAnalyzer.indexError.message=Failed to index GPS trackpoint artifact for keyword search."})
|
|
||||||
private static void findGeoLocationsInFile(File file, AbstractFile f) {
|
|
||||||
byte[] bytes; // will temporarily hold bytes to be converted into the correct data types
|
|
||||||
|
|
||||||
try {
|
|
||||||
InputStream inputStream = new FileInputStream(file);
|
|
||||||
|
|
||||||
bytes = new byte[2]; // version
|
|
||||||
inputStream.read(bytes);
|
|
||||||
|
|
||||||
bytes = new byte[2];
|
|
||||||
inputStream.read(bytes); //number of location entries
|
|
||||||
|
|
||||||
int iterations = new BigInteger(bytes).intValue();
|
|
||||||
|
|
||||||
for (int i = 0; i < iterations; i++) { //loop through every entry
|
|
||||||
bytes = new byte[2];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
|
|
||||||
bytes = new byte[1];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
while (new BigInteger(bytes).intValue() != 0) { //pass through non important values until the start of accuracy(around 7-10 bytes)
|
|
||||||
if (0 > inputStream.read(bytes)) {
|
|
||||||
break; /// we've passed the end of the file, so stop
|
|
||||||
}
|
|
||||||
}
|
|
||||||
bytes = new byte[3];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
if (new BigInteger(bytes).intValue() <= 0) {//This refers to a location that could not be calculated.
|
|
||||||
bytes = new byte[28]; //read rest of the row's bytes
|
|
||||||
inputStream.read(bytes);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
String accuracy = "" + new BigInteger(bytes).intValue();
|
|
||||||
|
|
||||||
bytes = new byte[4];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
String confidence = "" + new BigInteger(bytes).intValue();
|
|
||||||
|
|
||||||
bytes = new byte[8];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
double latitude = toDouble(bytes);
|
|
||||||
|
|
||||||
bytes = new byte[8];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
double longitude = toDouble(bytes);
|
|
||||||
|
|
||||||
bytes = new byte[8];
|
|
||||||
inputStream.read(bytes);
|
|
||||||
Long timestamp = new BigInteger(bytes).longValue() / 1000;
|
|
||||||
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, moduleName, latitude));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, moduleName, longitude));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, timestamp));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName,
|
|
||||||
NbBundle.getMessage(CacheLocationAnalyzer.class,
|
|
||||||
"CacheLocationAnalyzer.bbAttribute.fileLocationHistory",
|
|
||||||
file.getName())));
|
|
||||||
|
|
||||||
//Not storing these for now.
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),moduleName, confidence));
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.CacheLocationAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Cached GPS locations to Blackboard", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static double toDouble(byte[] bytes) {
|
|
||||||
return ByteBuffer.wrap(bytes).getDouble();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,184 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.io.IOException;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates a variety of different call log databases, parses them, and populates
|
|
||||||
* the blackboard.
|
|
||||||
*/
|
|
||||||
class CallLogAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(CallLogAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
private static final IngestServices services = IngestServices.getInstance();
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* the names of tables that potentially hold call logs in the dbs
|
|
||||||
*/
|
|
||||||
private static final Iterable<String> tableNames = Arrays.asList("calls", "logs"); //NON-NLS
|
|
||||||
|
|
||||||
public static void findCallLogs(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
List<AbstractFile> absFiles = fileManager.findFiles(dataSource, "logs.db"); //NON-NLS
|
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db")); //NON-NLS
|
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db")); //NON-NLS
|
|
||||||
for (AbstractFile abstractFile : absFiles) {
|
|
||||||
try {
|
|
||||||
File file = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, file, context::dataSourceIngestIsCancelled);
|
|
||||||
findCallLogsInDB(file.toString(), abstractFile);
|
|
||||||
} catch (IOException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error writing temporary call log db to disk", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding call logs", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"CallLogAnalyzer.indexError.message=Failed to index call log artifact for keyword search."})
|
|
||||||
private static void findCallLogsInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
|
||||||
try (Connection connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
Statement statement = connection.createStatement();) {
|
|
||||||
|
|
||||||
for (String tableName : tableNames) {
|
|
||||||
try (ResultSet resultSet = statement.executeQuery(
|
|
||||||
"SELECT number,date,duration,type, name FROM " + tableName + " ORDER BY date DESC;");) { //NON-NLS
|
|
||||||
logger.log(Level.INFO, "Reading call log from table {0} in db {1}", new Object[]{tableName, DatabasePath}); //NON-NLS
|
|
||||||
while (resultSet.next()) {
|
|
||||||
Long date = resultSet.getLong("date") / 1000;
|
|
||||||
final CallDirection direction = CallDirection.fromType(resultSet.getInt("type")); //NON-NLS
|
|
||||||
String directionString = direction != null ? direction.getDisplayName() : "";
|
|
||||||
final String number = resultSet.getString("number"); //NON-NLS
|
|
||||||
final long duration = resultSet.getLong("duration"); //NON-NLS //duration of call is in seconds
|
|
||||||
final String name = resultSet.getString("name"); //NON-NLS // name of person dialed or called. null if unregistered
|
|
||||||
|
|
||||||
try {
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG); //create a call log and then add attributes from result set.
|
|
||||||
if (direction == CallDirection.OUTGOING) {
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, number));
|
|
||||||
} else { /// Covers INCOMING and MISSED
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, number));
|
|
||||||
}
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, moduleName, date));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, moduleName, duration + date));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, directionString));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
|
||||||
|
|
||||||
bbartifacts.add(bba);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.CallLogAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error posting call log record to the Blackboard", ex); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.log(Level.WARNING, String.format("Could not read table %s in db %s", tableName, DatabasePath), e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + DatabasePath, e); //NON-NLS
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (!bbartifacts.isEmpty()) {
|
|
||||||
services.fireModuleDataEvent(new ModuleDataEvent(
|
|
||||||
moduleName,
|
|
||||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG, bbartifacts));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static enum CallDirection {
|
|
||||||
|
|
||||||
INCOMING(1, "Incoming"), OUTGOING(2, "Outgoing"), MISSED(3, "Missed"); //NON-NLS
|
|
||||||
|
|
||||||
private final int type;
|
|
||||||
|
|
||||||
private final String displayName;
|
|
||||||
|
|
||||||
public String getDisplayName() {
|
|
||||||
return displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
private CallDirection(int type, String displayName) {
|
|
||||||
this.type = type;
|
|
||||||
this.displayName = displayName;
|
|
||||||
}
|
|
||||||
|
|
||||||
static CallDirection fromType(int t) {
|
|
||||||
switch (t) {
|
|
||||||
case 1:
|
|
||||||
return INCOMING;
|
|
||||||
case 2:
|
|
||||||
return OUTGOING;
|
|
||||||
case 3:
|
|
||||||
return MISSED;
|
|
||||||
default:
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,195 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DatabaseMetaData;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates a variety of different contacts databases, parses them, and populates
|
|
||||||
* the blackboard.
|
|
||||||
*/
|
|
||||||
class ContactAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(ContactAnalyzer.class.getName());
|
|
||||||
private static final IngestServices services = IngestServices.getInstance();
|
|
||||||
|
|
||||||
public static void findContacts(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
List<AbstractFile> absFiles;
|
|
||||||
try {
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "contacts.db"); //NON-NLS
|
|
||||||
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db")); //NON-NLS
|
|
||||||
if (absFiles.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (AbstractFile AF : absFiles) {
|
|
||||||
try {
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), AF.getName());
|
|
||||||
ContentUtils.writeToFile(AF, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
findContactsInDB(jFile.toString(), AF);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Contacts", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding Contacts", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* @param databasePath
|
|
||||||
* @param fId Will create artifact from a database given by the
|
|
||||||
* path The fileId will be the Abstract file associated
|
|
||||||
* with the artifacts
|
|
||||||
*/
|
|
||||||
@Messages({"ContactAnalyzer.indexError.message=Failed to index contact artifact for keyword search."})
|
|
||||||
private static void findContactsInDB(String databasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
Blackboard blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
|
|
||||||
if (databasePath == null || databasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
// get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype)
|
|
||||||
//sorted by name, so phonenumber/email would be consecutive for a person if they exist.
|
|
||||||
// check if contacts.name_raw_contact_id exists. Modify the query accordingly.
|
|
||||||
Boolean column_found = false;
|
|
||||||
DatabaseMetaData metadata = connection.getMetaData();
|
|
||||||
ResultSet columnListResultSet = metadata.getColumns(null, null, "contacts", null); //NON-NLS
|
|
||||||
while (columnListResultSet.next()) {
|
|
||||||
if (columnListResultSet.getString("COLUMN_NAME").equals("name_raw_contact_id")) { //NON-NLS
|
|
||||||
column_found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (column_found) {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT mimetype,data1, name_raw_contact.display_name AS display_name \n" //NON-NLS
|
|
||||||
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" //NON-NLS
|
|
||||||
+ "JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id) " //NON-NLS
|
|
||||||
+ "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" //NON-NLS
|
|
||||||
+ "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" //NON-NLS
|
|
||||||
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" //NON-NLS
|
|
||||||
+ "ORDER BY name_raw_contact.display_name ASC;"); //NON-NLS
|
|
||||||
} else {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT mimetype,data1, raw_contacts.display_name AS display_name \n" //NON-NLS
|
|
||||||
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n" //NON-NLS
|
|
||||||
+ "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n" //NON-NLS
|
|
||||||
+ "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n" //NON-NLS
|
|
||||||
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n" //NON-NLS
|
|
||||||
+ "ORDER BY raw_contacts.display_name ASC;"); //NON-NLS
|
|
||||||
}
|
|
||||||
|
|
||||||
BlackboardArtifact bba;
|
|
||||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
|
||||||
String name;
|
|
||||||
String oldName = "";
|
|
||||||
String mimetype; // either phone or email
|
|
||||||
String data1; // the phone number or email
|
|
||||||
while (resultSet.next()) {
|
|
||||||
name = resultSet.getString("display_name"); //NON-NLS
|
|
||||||
data1 = resultSet.getString("data1"); //NON-NLS
|
|
||||||
mimetype = resultSet.getString("mimetype"); //NON-NLS
|
|
||||||
if (name.equals(oldName) == false) {
|
|
||||||
bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT);
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, name));
|
|
||||||
}
|
|
||||||
if (mimetype.equals("vnd.android.cursor.item/phone_v2")) { //NON-NLS
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, moduleName, data1));
|
|
||||||
} else {
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, moduleName, data1));
|
|
||||||
}
|
|
||||||
oldName = name;
|
|
||||||
|
|
||||||
bbartifacts.add(bba);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.ContactAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
} catch (SQLException e) {
|
|
||||||
logger.log(Level.WARNING, "Unable to execute contacts SQL query against {0} : {1}", new Object[]{databasePath, e}); //NON-NLS
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error posting to blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
if (!bbartifacts.isEmpty()) {
|
|
||||||
services.fireModuleDataEvent(new ModuleDataEvent(
|
|
||||||
moduleName,
|
|
||||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, bbartifacts));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,170 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds and parses the Google Maps database.
|
|
||||||
*/
|
|
||||||
class GoogleMapLocationAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(GoogleMapLocationAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
public static void findGeoLocations(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
List<AbstractFile> absFiles;
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "da_destination_history"); //NON-NLS
|
|
||||||
if (absFiles.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
for (AbstractFile abstractFile : absFiles) {
|
|
||||||
try {
|
|
||||||
File jFile = new java.io.File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
findGeoLocationsInDB(jFile.toString(), abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Google map locations", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding Google map locations", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"GoogleMapLocationAnalyzer.indexError.message=Failed to index GPS route artifact for keyword search."})
|
|
||||||
private static void findGeoLocationsInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT time,dest_lat,dest_lng,dest_title,dest_address,source_lat,source_lng FROM destination_history;"); //NON-NLS
|
|
||||||
|
|
||||||
while (resultSet.next()) {
|
|
||||||
Long time = Long.valueOf(resultSet.getString("time")) / 1000; //NON-NLS
|
|
||||||
String dest_title = resultSet.getString("dest_title"); //NON-NLS
|
|
||||||
String dest_address = resultSet.getString("dest_address"); //NON-NLS
|
|
||||||
|
|
||||||
double dest_lat = convertGeo(resultSet.getString("dest_lat")); //NON-NLS
|
|
||||||
double dest_lng = convertGeo(resultSet.getString("dest_lng")); //NON-NLS
|
|
||||||
double source_lat = convertGeo(resultSet.getString("source_lat")); //NON-NLS
|
|
||||||
double source_lng = convertGeo(resultSet.getString("source_lng")); //NON-NLS
|
|
||||||
|
|
||||||
// bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);//src
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, "Source"));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, source_lat));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, source_lng));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), moduleName, time));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DESCRIPTION.getTypeID(), moduleName, "Google Maps History"));
|
|
||||||
//
|
|
||||||
// bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT);//dest
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY.getTypeID(), moduleName, "Destination"));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID(), moduleName, time));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE.getTypeID(), moduleName, dest_lat));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE.getTypeID(), moduleName, dest_lng));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME.getTypeID(), moduleName, dest_title));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION.getTypeID(), moduleName, dest_address));
|
|
||||||
// bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME.getTypeID(), moduleName, "Google Maps History"));
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE);
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, moduleName,
|
|
||||||
NbBundle.getMessage(GoogleMapLocationAnalyzer.class,
|
|
||||||
"GoogleMapLocationAnalyzer.bbAttribute.destination")));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, time));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, moduleName, dest_lat));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, moduleName, dest_lng));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, moduleName, source_lat));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, moduleName, source_lng));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, dest_title));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, moduleName, dest_address));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, moduleName,
|
|
||||||
NbBundle.getMessage(GoogleMapLocationAnalyzer.class,
|
|
||||||
"GoogleMapLocationAnalyzer.bbAttribute.googleMapsHistory")));
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.GoogleMapLocationAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Google map locations to the Blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing the database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//add periods 6 decimal places before the end.
|
|
||||||
private static double convertGeo(String s) {
|
|
||||||
if (s.length() > 6) {
|
|
||||||
return Double.valueOf(s.substring(0, s.length() - 6) + "." + s.substring(s.length() - 6, s.length()));
|
|
||||||
} else {
|
|
||||||
return Double.valueOf(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,154 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.apache.commons.codec.binary.Base64;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Locates database for the Tango app and adds info to blackboard.
|
|
||||||
*/
|
|
||||||
class TangoMessageAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(TangoMessageAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
public static void findTangoMessages(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
List<AbstractFile> absFiles;
|
|
||||||
try {
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "tc.db"); //NON-NLS
|
|
||||||
for (AbstractFile abstractFile : absFiles) {
|
|
||||||
try {
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
findTangoMessagesInDB(jFile.toString(), abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Tango messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding Tango messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"TangoMessageAnalyzer.indexError.message=Failed to index Tango message artifact for keyword search."})
|
|
||||||
private static void findTangoMessagesInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT conv_id, create_time,direction,payload FROM messages ORDER BY create_time DESC;"); //NON-NLS
|
|
||||||
|
|
||||||
String conv_id; // seems to wrap around the message found in payload after decoding from base-64
|
|
||||||
String direction; // 1 incoming, 2 outgoing
|
|
||||||
String payload; // seems to be a base64 message wrapped by the conv_id
|
|
||||||
|
|
||||||
while (resultSet.next()) {
|
|
||||||
conv_id = resultSet.getString("conv_id"); //NON-NLS
|
|
||||||
Long create_time = Long.valueOf(resultSet.getString("create_time")) / 1000; //NON-NLS
|
|
||||||
if (resultSet.getString("direction").equals("1")) { //NON-NLS
|
|
||||||
direction = "Incoming"; //NON-NLS
|
|
||||||
} else {
|
|
||||||
direction = "Outgoing"; //NON-NLS
|
|
||||||
}
|
|
||||||
payload = resultSet.getString("payload"); //NON-NLS
|
|
||||||
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create a call log and then add attributes from result set.
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, create_time));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName, direction));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, decodeMessage(conv_id, payload)));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName,
|
|
||||||
NbBundle.getMessage(TangoMessageAnalyzer.class,
|
|
||||||
"TangoMessageAnalyzer.bbAttribute.tangoMessage")));
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.TangoMessageAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing Tango messages to the Blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//take the message string which is wrapped by a certain string, and return the text enclosed.
|
|
||||||
private static String decodeMessage(String wrapper, String message) {
|
|
||||||
String result = "";
|
|
||||||
byte[] decoded = Base64.decodeBase64(message);
|
|
||||||
try {
|
|
||||||
String Z = new String(decoded, "UTF-8");
|
|
||||||
result = Z.split(wrapper)[1];
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error decoding a Tango message", e); //NON-NLS
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,167 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Collection;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestServices;
|
|
||||||
import org.sleuthkit.autopsy.ingest.ModuleDataEvent;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds database with SMS/MMS messages and adds them to blackboard.
|
|
||||||
*/
|
|
||||||
class TextMessageAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(TextMessageAnalyzer.class.getName());
|
|
||||||
private static final IngestServices services = IngestServices.getInstance();
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
public static void findTexts(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
|
|
||||||
List<AbstractFile> absFiles = fileManager.findFiles(dataSource, "mmssms.db"); //NON-NLS
|
|
||||||
for (AbstractFile abstractFile : absFiles) {
|
|
||||||
try {
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
findTextsInDB(jFile.toString(), abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing text messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding text messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"TextMessageAnalyzer.indexError.message=Failed to index text message artifact for keyword search."})
|
|
||||||
private static void findTextsInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //NON-NLS //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
Collection<BlackboardArtifact> bbartifacts = new ArrayList<>();
|
|
||||||
try {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT address,date,read,type,subject,body FROM sms;"); //NON-NLS
|
|
||||||
|
|
||||||
String address; // may be phone number, or other addresses
|
|
||||||
|
|
||||||
String direction; // message received in inbox = 1, message sent = 2
|
|
||||||
String subject;//message subject
|
|
||||||
Integer read; // may be unread = 0, read = 1
|
|
||||||
String body; //message body
|
|
||||||
while (resultSet.next()) {
|
|
||||||
address = resultSet.getString("address"); //NON-NLS
|
|
||||||
Long date = Long.valueOf(resultSet.getString("date")) / 1000; //NON-NLS
|
|
||||||
|
|
||||||
read = resultSet.getInt("read"); //NON-NLS
|
|
||||||
subject = resultSet.getString("subject"); //NON-NLS
|
|
||||||
body = resultSet.getString("body"); //NON-NLS
|
|
||||||
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create Message artifact and then add attributes from result set.
|
|
||||||
if (resultSet.getString("type").equals("1")) { //NON-NLS
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName,
|
|
||||||
NbBundle.getMessage(TextMessageAnalyzer.class,
|
|
||||||
"TextMessageAnalyzer.bbAttribute.incoming")));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, moduleName, address));
|
|
||||||
} else {
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, moduleName,
|
|
||||||
NbBundle.getMessage(TextMessageAnalyzer.class,
|
|
||||||
"TextMessageAnalyzer.bbAttribute.outgoing")));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, moduleName, address));
|
|
||||||
}
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, date));
|
|
||||||
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, moduleName, read));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, moduleName, subject));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, body));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName,
|
|
||||||
NbBundle.getMessage(TextMessageAnalyzer.class,
|
|
||||||
"TextMessageAnalyzer.bbAttribute.smsMessage")));
|
|
||||||
|
|
||||||
bbartifacts.add(bba);
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.TextMessageAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing text messages to Blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
if (!bbartifacts.isEmpty()) {
|
|
||||||
services.fireModuleDataEvent(new ModuleDataEvent(
|
|
||||||
moduleName,
|
|
||||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,140 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2014 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.android;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.sql.Connection;
|
|
||||||
import java.sql.DriverManager;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.sql.Statement;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import org.openide.util.NbBundle;
|
|
||||||
import org.openide.util.NbBundle.Messages;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.Blackboard;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.services.FileManager;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.ingest.IngestJobContext;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.Content;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Finds database for words with friends, parses it, and adds info to
|
|
||||||
* blackboard.
|
|
||||||
*/
|
|
||||||
class WWFMessageAnalyzer {
|
|
||||||
|
|
||||||
private static final String moduleName = AndroidModuleFactory.getModuleName();
|
|
||||||
private static final Logger logger = Logger.getLogger(WWFMessageAnalyzer.class.getName());
|
|
||||||
private static Blackboard blackboard;
|
|
||||||
|
|
||||||
public static void findWWFMessages(Content dataSource, FileManager fileManager,
|
|
||||||
IngestJobContext context) {
|
|
||||||
List<AbstractFile> absFiles;
|
|
||||||
blackboard = Case.getCurrentCase().getServices().getBlackboard();
|
|
||||||
try {
|
|
||||||
absFiles = fileManager.findFiles(dataSource, "WordsFramework"); //NON-NLS
|
|
||||||
|
|
||||||
for (AbstractFile abstractFile : absFiles) {
|
|
||||||
try {
|
|
||||||
File jFile = new File(Case.getCurrentCase().getTempDirectory(), abstractFile.getName());
|
|
||||||
ContentUtils.writeToFile(abstractFile, jFile, context::dataSourceIngestIsCancelled);
|
|
||||||
|
|
||||||
findWWFMessagesInDB(jFile.toString(), abstractFile);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing WWF messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error finding WWF messages", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Messages({"WWFMessageAnalyzer.indexError.message=Failed to index WWF message artifact for keyword search."})
|
|
||||||
private static void findWWFMessagesInDB(String DatabasePath, AbstractFile f) {
|
|
||||||
Connection connection = null;
|
|
||||||
ResultSet resultSet = null;
|
|
||||||
Statement statement = null;
|
|
||||||
|
|
||||||
if (DatabasePath == null || DatabasePath.isEmpty()) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
Class.forName("org.sqlite.JDBC"); //load JDBC driver
|
|
||||||
connection = DriverManager.getConnection("jdbc:sqlite:" + DatabasePath); //NON-NLS
|
|
||||||
statement = connection.createStatement();
|
|
||||||
} catch (ClassNotFoundException | SQLException e) {
|
|
||||||
logger.log(Level.SEVERE, "Error opening database", e); //NON-NLS
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
resultSet = statement.executeQuery(
|
|
||||||
"SELECT message,strftime('%s' ,created_at) as datetime,user_id,game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;"); //NON-NLS
|
|
||||||
|
|
||||||
String message; // WWF Message
|
|
||||||
String user_id; // the ID of the user who sent the message.
|
|
||||||
String game_id; // ID of the game which the the message was sent.
|
|
||||||
|
|
||||||
while (resultSet.next()) {
|
|
||||||
message = resultSet.getString("message"); //NON-NLS
|
|
||||||
Long created_at = resultSet.getLong("datetime"); //NON-NLS
|
|
||||||
user_id = resultSet.getString("user_id"); //NON-NLS
|
|
||||||
game_id = resultSet.getString("game_id"); //NON-NLS
|
|
||||||
|
|
||||||
BlackboardArtifact bba = f.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); //create a call log and then add attributes from result set.
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, moduleName, created_at));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, moduleName, user_id));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, moduleName, game_id));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, moduleName, message));
|
|
||||||
bba.addAttribute(new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, moduleName,
|
|
||||||
NbBundle.getMessage(WWFMessageAnalyzer.class,
|
|
||||||
"WWFMessageAnalyzer.bbAttribute.wordsWithFriendsMsg")));
|
|
||||||
|
|
||||||
try {
|
|
||||||
// index the artifact for keyword search
|
|
||||||
blackboard.indexArtifact(bba);
|
|
||||||
} catch (Blackboard.BlackboardException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unable to index blackboard artifact " + bba.getArtifactID(), ex); //NON-NLS
|
|
||||||
MessageNotifyUtil.Notify.error(
|
|
||||||
Bundle.WWFMessageAnalyzer_indexError_message(), bba.getDisplayName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error parsing WWF messages to the Blackboard", e); //NON-NLS
|
|
||||||
} finally {
|
|
||||||
try {
|
|
||||||
if (resultSet != null) {
|
|
||||||
resultSet.close();
|
|
||||||
}
|
|
||||||
statement.close();
|
|
||||||
connection.close();
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.SEVERE, "Error closing database", e); //NON-NLS
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -31,7 +31,6 @@ EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err=Ppt conta
|
|||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err=Pptx container could not be initialized while reading: {0}
|
EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err=Pptx container could not be initialized while reading: {0}
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err=Xls container could not be initialized while reading: {0}
|
EmbeddedFileExtractorIngestModule.ImageExtractor.xlsContainer.init.err=Xls container could not be initialized while reading: {0}
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err=Xlsx container could not be initialized while reading: {0}
|
EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err=Xlsx container could not be initialized while reading: {0}
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err=Embedded File Extractor is unable to read content of {0}
|
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg=Unable to add the derived files to the database.
|
EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg=Unable to add the derived files to the database.
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg=Could not get path for image extraction from Abstract File\: {0}
|
EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg=Could not get path for image extraction from Abstract File\: {0}
|
||||||
EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg=Could not get path for image extraction from Abstract File: {0}
|
EmbeddedFileExtractorIngestModule.ImageExtractor.getOutputFolderPath.exception.msg=Could not get path for image extraction from Abstract File: {0}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011-2015 Basis Technology Corp.
|
* Copyright 2011-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -25,6 +25,8 @@ import java.nio.file.Paths;
|
|||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
|
import org.apache.poi.OldFileFormatException;
|
||||||
|
import org.apache.poi.POIXMLException;
|
||||||
import org.apache.poi.hslf.model.Picture;
|
import org.apache.poi.hslf.model.Picture;
|
||||||
import org.apache.poi.hslf.usermodel.PictureData;
|
import org.apache.poi.hslf.usermodel.PictureData;
|
||||||
import org.apache.poi.hslf.usermodel.SlideShow;
|
import org.apache.poi.hslf.usermodel.SlideShow;
|
||||||
@ -120,7 +122,7 @@ class ImageExtractor {
|
|||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
|
logger.log(Level.SEVERE, "Error executing FileTypeDetector.getFileType()", ex); // NON-NLS
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -152,7 +154,7 @@ class ImageExtractor {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} catch (TskCoreException e) {
|
} catch (TskCoreException e) {
|
||||||
logger.log(Level.WARNING, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
|
logger.log(Level.SEVERE, String.format("Error checking if file already has been processed, skipping: %s", parentFileName), e); //NON-NLS
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
switch (abstractFileExtractionFormat) {
|
switch (abstractFileExtractionFormat) {
|
||||||
@ -189,7 +191,7 @@ class ImageExtractor {
|
|||||||
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
|
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
|
||||||
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
|
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
|
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImage.addToDB.exception.msg"), ex); //NON-NLS
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!listOfExtractedImages.isEmpty()) {
|
if (!listOfExtractedImages.isEmpty()) {
|
||||||
@ -207,24 +209,24 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromDoc(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromDoc(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
List<org.apache.poi.hwpf.usermodel.Picture> listOfAllPictures;
|
||||||
HWPFDocument doc = null;
|
|
||||||
try {
|
try {
|
||||||
doc = new HWPFDocument(new ReadContentInputStream(af));
|
HWPFDocument doc = new HWPFDocument(new ReadContentInputStream(af));
|
||||||
|
PicturesTable pictureTable = doc.getPicturesTable();
|
||||||
|
listOfAllPictures = pictureTable.getAllPictures();
|
||||||
|
} catch (OldFileFormatException | IOException ex) {
|
||||||
|
// OldFileFormatException:
|
||||||
|
// Thrown when the document version is unsupported (Word 95 and
|
||||||
|
// older)
|
||||||
|
|
||||||
|
// IOException:
|
||||||
|
// Thrown when the document has issues being read.
|
||||||
|
|
||||||
|
return null;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
PicturesTable pictureTable = null;
|
|
||||||
List<org.apache.poi.hwpf.usermodel.Picture> listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
pictureTable = doc.getPicturesTable();
|
|
||||||
listOfAllPictures = pictureTable.getAllPictures();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -237,15 +239,13 @@ class ImageExtractor {
|
|||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (org.apache.poi.hwpf.usermodel.Picture picture : listOfAllPictures) {
|
for (org.apache.poi.hwpf.usermodel.Picture picture : listOfAllPictures) {
|
||||||
String fileName = picture.suggestFullFileName();
|
String fileName = picture.suggestFullFileName();
|
||||||
try {
|
try {
|
||||||
data = picture.getContent();
|
data = picture.getContent();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
||||||
@ -265,21 +265,22 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromDocx(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromDocx(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
List<XWPFPictureData> listOfAllPictures = null;
|
||||||
XWPFDocument docx = null;
|
|
||||||
try {
|
try {
|
||||||
docx = new XWPFDocument(new ReadContentInputStream(af));
|
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) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS
|
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<XWPFPictureData> listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
listOfAllPictures = docx.getAllPictures();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -292,18 +293,15 @@ class ImageExtractor {
|
|||||||
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
||||||
}
|
}
|
||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (XWPFPictureData xwpfPicture : listOfAllPictures) {
|
for (XWPFPictureData xwpfPicture : listOfAllPictures) {
|
||||||
String fileName = xwpfPicture.getFileName();
|
String fileName = xwpfPicture.getFileName();
|
||||||
try {
|
try {
|
||||||
data = xwpfPicture.getData();
|
data = xwpfPicture.getData();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
||||||
@ -321,23 +319,22 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromPpt(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromPpt(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
PictureData[] listOfAllPictures = null;
|
||||||
SlideShow ppt = null;
|
|
||||||
try {
|
try {
|
||||||
ppt = new SlideShow(new ReadContentInputStream(af));
|
SlideShow ppt = new SlideShow(new ReadContentInputStream(af));
|
||||||
|
listOfAllPictures = ppt.getPictureData();
|
||||||
|
} catch (OldFileFormatException | IOException ex) {
|
||||||
|
// OldFileFormatException:
|
||||||
|
// Thrown when the document version is unsupported
|
||||||
|
|
||||||
|
// IOException:
|
||||||
|
// Thrown when the document has issues being read
|
||||||
|
|
||||||
|
return null;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
//extract all pictures contained in the presentation
|
|
||||||
PictureData[] listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
listOfAllPictures = ppt.getPictureData();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -350,14 +347,13 @@ class ImageExtractor {
|
|||||||
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
||||||
}
|
}
|
||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// extract the images to the above initialized outputFolder.
|
// extract the images to the above initialized outputFolder.
|
||||||
// extraction path - outputFolder/image_number.ext
|
// extraction path - outputFolder/image_number.ext
|
||||||
int i = 0;
|
int i = 0;
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (PictureData pictureData : listOfAllPictures) {
|
for (PictureData pictureData : listOfAllPictures) {
|
||||||
|
|
||||||
@ -388,8 +384,6 @@ class ImageExtractor {
|
|||||||
try {
|
try {
|
||||||
data = pictureData.getData();
|
data = pictureData.getData();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
||||||
@ -408,21 +402,22 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromPptx(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromPptx(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
List<XSLFPictureData> listOfAllPictures = null;
|
||||||
XMLSlideShow pptx;
|
|
||||||
try {
|
try {
|
||||||
pptx = new XMLSlideShow(new ReadContentInputStream(af));
|
XMLSlideShow pptx = new XMLSlideShow(new ReadContentInputStream(af));
|
||||||
|
listOfAllPictures = pptx.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) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS
|
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS
|
||||||
return null;
|
|
||||||
}
|
|
||||||
List<XSLFPictureData> listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
listOfAllPictures = pptx.getAllPictures();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -435,11 +430,10 @@ class ImageExtractor {
|
|||||||
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
||||||
}
|
}
|
||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (XSLFPictureData xslsPicture : listOfAllPictures) {
|
for (XSLFPictureData xslsPicture : listOfAllPictures) {
|
||||||
|
|
||||||
@ -449,8 +443,6 @@ class ImageExtractor {
|
|||||||
try {
|
try {
|
||||||
data = xslsPicture.getData();
|
data = xslsPicture.getData();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
|
||||||
@ -471,23 +463,22 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromXls(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromXls(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
|
||||||
|
|
||||||
Workbook xls;
|
|
||||||
try {
|
try {
|
||||||
xls = new HSSFWorkbook(new ReadContentInputStream(af));
|
Workbook xls = new HSSFWorkbook(new ReadContentInputStream(af));
|
||||||
|
listOfAllPictures = xls.getAllPictures();
|
||||||
|
} catch (OldFileFormatException | IOException ex) {
|
||||||
|
// OldFileFormatException:
|
||||||
|
// Thrown when the document version is unsupported
|
||||||
|
|
||||||
|
// IOException:
|
||||||
|
// Thrown when the document has issues being read
|
||||||
|
|
||||||
|
return null;
|
||||||
} catch (Throwable ex) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
listOfAllPictures = xls.getAllPictures();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -500,20 +491,17 @@ class ImageExtractor {
|
|||||||
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
||||||
}
|
}
|
||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
|
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
|
||||||
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
|
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
|
||||||
try {
|
try {
|
||||||
data = pictureData.getData();
|
data = pictureData.getData();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
||||||
@ -533,22 +521,22 @@ class ImageExtractor {
|
|||||||
* extracted.
|
* extracted.
|
||||||
*/
|
*/
|
||||||
private List<ExtractedImage> extractImagesFromXlsx(AbstractFile af) {
|
private List<ExtractedImage> extractImagesFromXlsx(AbstractFile af) {
|
||||||
List<ExtractedImage> listOfExtractedImages;
|
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
|
||||||
Workbook xlsx;
|
|
||||||
try {
|
try {
|
||||||
xlsx = new XSSFWorkbook(new ReadContentInputStream(af));
|
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) {
|
} catch (Throwable ex) {
|
||||||
// instantiating POI containers throw RuntimeExceptions
|
// instantiating POI containers throw RuntimeExceptions
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS
|
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
|
|
||||||
try {
|
|
||||||
listOfAllPictures = xlsx.getAllPictures();
|
|
||||||
} catch (Exception ex) {
|
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -561,20 +549,17 @@ class ImageExtractor {
|
|||||||
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
outputFolderPath = getOutputFolderPath(this.parentFileName);
|
||||||
}
|
}
|
||||||
if (outputFolderPath == null) {
|
if (outputFolderPath == null) {
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
listOfExtractedImages = new ArrayList<>();
|
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
|
||||||
byte[] data = null;
|
byte[] data = null;
|
||||||
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
|
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
|
||||||
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension();
|
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension();
|
||||||
try {
|
try {
|
||||||
data = pictureData.getData();
|
data = pictureData.getData();
|
||||||
} catch (Exception ex) {
|
} catch (Exception ex) {
|
||||||
// log internal Java and Apache errors as WARNING
|
|
||||||
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.processing.err", af.getName()), ex); //NON-NLS
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-2014 Basis Technology Corp.
|
* Copyright 2013-2014 Basis Technology Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
|||||||
public final class ReportBranding implements ReportBrandingProviderI {
|
public final class ReportBranding implements ReportBrandingProviderI {
|
||||||
|
|
||||||
//property names
|
//property names
|
||||||
private static final String AGENCY_LOGO_PATH_PROP = "AgencyLogoPath"; //NON-NLS
|
public static final String AGENCY_LOGO_PATH_PROP = "AgencyLogoPath"; //NON-NLS
|
||||||
private static final String REPORT_TITLE_PROP = "ReportTitle"; //NON-NLS
|
private static final String REPORT_TITLE_PROP = "ReportTitle"; //NON-NLS
|
||||||
private static final String REPORT_FOOTER_PROP = "ReportFooter"; //NON-NLS
|
private static final String REPORT_FOOTER_PROP = "ReportFooter"; //NON-NLS
|
||||||
//default settings
|
//default settings
|
||||||
@ -46,7 +46,7 @@ public final class ReportBranding implements ReportBrandingProviderI {
|
|||||||
private static final String DEFAULT_REPORT_FOOTER = NbBundle
|
private static final String DEFAULT_REPORT_FOOTER = NbBundle
|
||||||
.getMessage(ReportBranding.class, "ReportBranding.defaultReportFooter.text");
|
.getMessage(ReportBranding.class, "ReportBranding.defaultReportFooter.text");
|
||||||
private String reportsBrandingDir; //dir with extracted reports branding resources
|
private String reportsBrandingDir; //dir with extracted reports branding resources
|
||||||
private static final String MODULE_NAME = ReportBranding.class.getSimpleName();
|
public static final String MODULE_NAME = ReportBranding.class.getSimpleName();
|
||||||
private static final Logger logger = Logger.getLogger(ReportBranding.class.getName());
|
private static final Logger logger = Logger.getLogger(ReportBranding.class.getName());
|
||||||
|
|
||||||
// this is static so that it can be set by another object
|
// this is static so that it can be set by another object
|
||||||
@ -130,7 +130,7 @@ public final class ReportBranding implements ReportBrandingProviderI {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setAgencyLogoPath(String path) {
|
public void setAgencyLogoPath(String path) {
|
||||||
// Use properties to persist the logo to use.
|
// Use properties to persist the logo to use.
|
||||||
// Should use static variable instead
|
// Should use static variable instead
|
||||||
ModuleSettings.setConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP, path);
|
ModuleSettings.setConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP, path);
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013 Basis Technology Corp.
|
* Copyright 2013 Basis Technology Corp.
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
/*
|
/*
|
||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012-2014 Basis Technology Corp.
|
* Copyright 2012-2014 Basis Technology Corp.
|
||||||
*
|
*
|
||||||
* Copyright 2012 42six Solutions.
|
* Copyright 2012 42six Solutions.
|
||||||
* Contact: aebadirad <at> 42six <dot> com
|
* Contact: aebadirad <at> 42six <dot> com
|
||||||
* Project Contact/Architect: carrier <at> sleuthkit <dot> org
|
* Project Contact/Architect: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
* You may obtain a copy of the License at
|
* You may obtain a copy of the License at
|
||||||
*
|
*
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
*
|
*
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
@ -32,6 +32,9 @@ import java.io.OutputStream;
|
|||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
import java.io.Writer;
|
import java.io.Writer;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
import java.nio.file.Paths;
|
||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -628,7 +631,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (totalCount == MAX_THUMBS_PER_PAGE) {
|
if (totalCount == MAX_THUMBS_PER_PAGE) {
|
||||||
// manually set the row count so the count of items shown in the
|
// manually set the row count so the count of items shown in the
|
||||||
// navigation page reflects the number of thumbnails instead of
|
// navigation page reflects the number of thumbnails instead of
|
||||||
// the number of rows.
|
// the number of rows.
|
||||||
rowCount = totalCount;
|
rowCount = totalCount;
|
||||||
@ -759,7 +762,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
localFilePath.append(File.separator);
|
localFilePath.append(File.separator);
|
||||||
localFilePath.append(fileName);
|
localFilePath.append(fileName);
|
||||||
|
|
||||||
// If the local file doesn't already exist, create it now.
|
// If the local file doesn't already exist, create it now.
|
||||||
// The existence check is necessary because it is possible to apply multiple tags with the same tagName to a file.
|
// The existence check is necessary because it is possible to apply multiple tags with the same tagName to a file.
|
||||||
File localFile = new File(localFilePath.toString());
|
File localFile = new File(localFilePath.toString());
|
||||||
if (!localFile.exists()) {
|
if (!localFile.exists()) {
|
||||||
@ -856,7 +859,7 @@ class ReportHTML implements TableReportModule {
|
|||||||
// use default Autopsy icon if custom icon is not set
|
// use default Autopsy icon if custom icon is not set
|
||||||
iconPath = "favicon.ico";
|
iconPath = "favicon.ico";
|
||||||
} else {
|
} else {
|
||||||
iconPath = "agency_logo"; //ref to writeNav() for agency_logo
|
iconPath = Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString(); //ref to writeNav() for agency_logo
|
||||||
}
|
}
|
||||||
index.append("<head>\n<title>").append(reportTitle).append(" ").append(
|
index.append("<head>\n<title>").append(reportTitle).append(" ").append(
|
||||||
NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getDisplayName())).append(
|
NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getDisplayName())).append(
|
||||||
@ -949,9 +952,8 @@ class ReportHTML implements TableReportModule {
|
|||||||
|
|
||||||
String agencyLogoPath = reportBranding.getAgencyLogoPath();
|
String agencyLogoPath = reportBranding.getAgencyLogoPath();
|
||||||
if (agencyLogoPath != null && !agencyLogoPath.isEmpty()) {
|
if (agencyLogoPath != null && !agencyLogoPath.isEmpty()) {
|
||||||
File from = new File(agencyLogoPath);
|
Path destinationPath = Paths.get(path);
|
||||||
File to = new File(path);
|
Files.copy(Files.newInputStream(Paths.get(agencyLogoPath)), destinationPath.resolve(Paths.get(agencyLogoPath).getFileName())); //NON-NLS
|
||||||
FileUtil.copyFile(FileUtil.toFileObject(from), FileUtil.toFileObject(to), "agency_logo"); //NON-NLS
|
|
||||||
}
|
}
|
||||||
|
|
||||||
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/favicon.ico"); //NON-NLS
|
in = getClass().getResourceAsStream("/org/sleuthkit/autopsy/report/images/favicon.ico"); //NON-NLS
|
||||||
@ -1049,7 +1051,9 @@ class ReportHTML implements TableReportModule {
|
|||||||
summary.append("<div class=\"title\">\n"); //NON-NLS
|
summary.append("<div class=\"title\">\n"); //NON-NLS
|
||||||
if (agencyLogoSet) {
|
if (agencyLogoSet) {
|
||||||
summary.append("<div class=\"left\">\n"); //NON-NLS
|
summary.append("<div class=\"left\">\n"); //NON-NLS
|
||||||
summary.append("<img src=\"agency_logo.png\" />\n"); //NON-NLS
|
summary.append("<img src=\"");
|
||||||
|
summary.append(Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString());
|
||||||
|
summary.append("\" />\n"); //NON-NLS
|
||||||
summary.append("</div>\n"); //NON-NLS
|
summary.append("</div>\n"); //NON-NLS
|
||||||
}
|
}
|
||||||
final String align = agencyLogoSet ? "right" : "left"; //NON-NLS NON-NLS
|
final String align = agencyLogoSet ? "right" : "left"; //NON-NLS NON-NLS
|
||||||
|
@ -156,7 +156,11 @@ public class SnapShotReportWriter {
|
|||||||
summaryContext.put("generationDateTime", new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(generationDate)); //NON-NLS
|
summaryContext.put("generationDateTime", new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(generationDate)); //NON-NLS
|
||||||
summaryContext.put("ingestRunning", IngestManager.getInstance().isIngestRunning()); //NON-NLS
|
summaryContext.put("ingestRunning", IngestManager.getInstance().isIngestRunning()); //NON-NLS
|
||||||
summaryContext.put("currentCase", currentCase); //NON-NLS
|
summaryContext.put("currentCase", currentCase); //NON-NLS
|
||||||
|
String agencyLogo = "agency_logo.png"; //default name for agency logo.
|
||||||
|
if (StringUtils.isNotBlank(reportBranding.getAgencyLogoPath())){
|
||||||
|
agencyLogo = Paths.get(reportBranding.getAgencyLogoPath()).getFileName().toString();
|
||||||
|
}
|
||||||
|
summaryContext.put("agencyLogoFileName", agencyLogo);
|
||||||
fillTemplateAndWrite("/org/sleuthkit/autopsy/timeline/snapshot/summary_template.html", "Summary", summaryContext, reportFolderPath.resolve("summary.html")); //NON-NLS
|
fillTemplateAndWrite("/org/sleuthkit/autopsy/timeline/snapshot/summary_template.html", "Summary", summaryContext, reportFolderPath.resolve("summary.html")); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -199,7 +203,7 @@ public class SnapShotReportWriter {
|
|||||||
}
|
}
|
||||||
String agencyLogoPath = reportBranding.getAgencyLogoPath();
|
String agencyLogoPath = reportBranding.getAgencyLogoPath();
|
||||||
if (StringUtils.isNotBlank(agencyLogoPath)) {
|
if (StringUtils.isNotBlank(agencyLogoPath)) {
|
||||||
Files.copy(Files.newInputStream(Paths.get(agencyLogoPath)), reportFolderPath.resolve("agency_logo.png")); //NON-NLS
|
Files.copy(Files.newInputStream(Paths.get(agencyLogoPath)), reportFolderPath.resolve(Paths.get(reportBranding.getAgencyLogoPath()).getFileName())); //NON-NLS
|
||||||
}
|
}
|
||||||
|
|
||||||
//copy navigation html
|
//copy navigation html
|
||||||
|
@ -13,7 +13,7 @@
|
|||||||
<div class="title">
|
<div class="title">
|
||||||
{{#reportBranding.getAgencyLogoPath}}
|
{{#reportBranding.getAgencyLogoPath}}
|
||||||
<div class="left">
|
<div class="left">
|
||||||
<img src="agency_logo.png" />
|
<img src="{{agencyLogoFileName}}" />
|
||||||
</div>
|
</div>
|
||||||
<div class="right">
|
<div class="right">
|
||||||
{{/reportBranding.getAgencyLogoPath}}
|
{{/reportBranding.getAgencyLogoPath}}
|
||||||
|
@ -234,7 +234,7 @@ public final class AutoIngestCasePanel extends JPanel {
|
|||||||
try {
|
try {
|
||||||
int selectedRow = casesTable.getSelectedRow();
|
int selectedRow = casesTable.getSelectedRow();
|
||||||
if (selectedRow >= 0 && selectedRow < casesTable.getRowCount()) {
|
if (selectedRow >= 0 && selectedRow < casesTable.getRowCount()) {
|
||||||
return Paths.get(caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.CASE.ordinal()).toString());
|
return Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(selectedRow), COLUMN_HEADERS.CASE.ordinal()).toString());
|
||||||
}
|
}
|
||||||
} catch (Exception ignored) {
|
} catch (Exception ignored) {
|
||||||
return null;
|
return null;
|
||||||
@ -251,7 +251,7 @@ public final class AutoIngestCasePanel extends JPanel {
|
|||||||
if (path != null) {
|
if (path != null) {
|
||||||
try {
|
try {
|
||||||
for (int row = 0; row < casesTable.getRowCount(); ++row) {
|
for (int row = 0; row < casesTable.getRowCount(); ++row) {
|
||||||
Path temp = Paths.get(caseTableModel.getValueAt(row, COLUMN_HEADERS.CASE.ordinal()).toString());
|
Path temp = Paths.get(caseTableModel.getValueAt(casesTable.convertRowIndexToModel(row), COLUMN_HEADERS.CASE.ordinal()).toString());
|
||||||
if (temp.compareTo(path) == 0) { // found it
|
if (temp.compareTo(path) == 0) { // found it
|
||||||
casesTable.setRowSelectionInterval(row, row);
|
casesTable.setRowSelectionInterval(row, row);
|
||||||
return;
|
return;
|
||||||
@ -546,9 +546,10 @@ public final class AutoIngestCasePanel extends JPanel {
|
|||||||
* @param evt -- The event that caused this to be called
|
* @param evt -- The event that caused this to be called
|
||||||
*/
|
*/
|
||||||
private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed
|
private void bnOpenActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnOpenActionPerformed
|
||||||
Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(casesTable.getSelectedRow(),
|
int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow());
|
||||||
|
Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow,
|
||||||
COLUMN_HEADERS.OUTPUTFOLDER.ordinal()),
|
COLUMN_HEADERS.OUTPUTFOLDER.ordinal()),
|
||||||
caseTableModel.getValueAt(casesTable.getSelectedRow(), COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
|
caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
|
||||||
openCase(caseMetadataFilePath);
|
openCase(caseMetadataFilePath);
|
||||||
}//GEN-LAST:event_bnOpenActionPerformed
|
}//GEN-LAST:event_bnOpenActionPerformed
|
||||||
|
|
||||||
@ -587,7 +588,7 @@ public final class AutoIngestCasePanel extends JPanel {
|
|||||||
}//GEN-LAST:event_rbWeeksItemStateChanged
|
}//GEN-LAST:event_rbWeeksItemStateChanged
|
||||||
|
|
||||||
private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed
|
private void bnShowLogActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_bnShowLogActionPerformed
|
||||||
int selectedRow = casesTable.getSelectedRow();
|
int selectedRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow());
|
||||||
int rowCount = casesTable.getRowCount();
|
int rowCount = casesTable.getRowCount();
|
||||||
if (selectedRow >= 0 && selectedRow < rowCount) {
|
if (selectedRow >= 0 && selectedRow < rowCount) {
|
||||||
String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal());
|
String thePath = (String) caseTableModel.getValueAt(selectedRow, COLUMN_HEADERS.OUTPUTFOLDER.ordinal());
|
||||||
@ -611,9 +612,10 @@ public final class AutoIngestCasePanel extends JPanel {
|
|||||||
|
|
||||||
private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked
|
private void casesTableMouseClicked(java.awt.event.MouseEvent evt) {//GEN-FIRST:event_casesTableMouseClicked
|
||||||
if (evt.getClickCount() == 2) {
|
if (evt.getClickCount() == 2) {
|
||||||
Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(casesTable.getSelectedRow(),
|
int modelRow = casesTable.convertRowIndexToModel(casesTable.getSelectedRow());
|
||||||
|
Path caseMetadataFilePath = Paths.get((String) caseTableModel.getValueAt(modelRow,
|
||||||
COLUMN_HEADERS.OUTPUTFOLDER.ordinal()),
|
COLUMN_HEADERS.OUTPUTFOLDER.ordinal()),
|
||||||
caseTableModel.getValueAt(casesTable.getSelectedRow(), COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
|
caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
|
||||||
openCase(caseMetadataFilePath);
|
openCase(caseMetadataFilePath);
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_casesTableMouseClicked
|
}//GEN-LAST:event_casesTableMouseClicked
|
||||||
|
@ -64,7 +64,6 @@ import javax.annotation.concurrent.ThreadSafe;
|
|||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
import org.sleuthkit.autopsy.casemodule.Case.CaseType;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
import org.sleuthkit.autopsy.casemodule.CaseActionException;
|
||||||
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
import org.sleuthkit.autopsy.casemodule.CaseMetadata;
|
||||||
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
import org.sleuthkit.autopsy.coordinationservice.CoordinationService;
|
||||||
@ -1880,14 +1879,8 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
*/
|
*/
|
||||||
private Case openCase() throws CoordinationServiceException, CaseManagementException, InterruptedException {
|
private Case openCase() throws CoordinationServiceException, CaseManagementException, InterruptedException {
|
||||||
Manifest manifest = currentJob.getManifest();
|
Manifest manifest = currentJob.getManifest();
|
||||||
String caseDisplayName = manifest.getCaseName();
|
String caseName = manifest.getCaseName();
|
||||||
String caseName;
|
SYS_LOGGER.log(Level.INFO, "Opening case {0} for {2}", new Object[]{caseName, manifest.getFilePath()});
|
||||||
try {
|
|
||||||
caseName = Case.displayNameToCaseName(caseDisplayName);
|
|
||||||
} catch (IllegalCaseNameException ex) {
|
|
||||||
throw new CaseManagementException(String.format("Error creating or opening case %s for %s", manifest.getCaseName(), manifest.getFilePath()), ex);
|
|
||||||
}
|
|
||||||
SYS_LOGGER.log(Level.INFO, "Opening case {0} ({1}) for {2}", new Object[]{caseDisplayName, caseName, manifest.getFilePath()});
|
|
||||||
currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE);
|
currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE);
|
||||||
/*
|
/*
|
||||||
* Acquire and hold a case name lock so that only one node at as
|
* Acquire and hold a case name lock so that only one node at as
|
||||||
@ -1917,16 +1910,16 @@ public final class AutoIngestManager extends Observable implements PropertyChang
|
|||||||
return caseForJob;
|
return caseForJob;
|
||||||
|
|
||||||
} catch (CaseActionException ex) {
|
} catch (CaseActionException ex) {
|
||||||
throw new CaseManagementException(String.format("Error creating or opening case %s (%s) for %s", manifest.getCaseName(), caseName, manifest.getFilePath()), ex);
|
throw new CaseManagementException(String.format("Error creating or opening case %s for %s", caseName, manifest.getFilePath()), ex);
|
||||||
} catch (IllegalStateException ex) {
|
} catch (IllegalStateException ex) {
|
||||||
/*
|
/*
|
||||||
* Deal with the unfortunate fact that
|
* Deal with the unfortunate fact that
|
||||||
* Case.getCurrentCase throws IllegalStateException.
|
* Case.getCurrentCase throws IllegalStateException.
|
||||||
*/
|
*/
|
||||||
throw new CaseManagementException(String.format("Error getting current case %s (%s) for %s", caseName, manifest.getCaseName(), manifest.getFilePath()), ex);
|
throw new CaseManagementException(String.format("Error getting current case %s for %s", caseName, manifest.getFilePath()), ex);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
throw new CaseManagementException(String.format("Timed out acquiring case name lock for %s for %s", manifest.getCaseName(), manifest.getFilePath()));
|
throw new CaseManagementException(String.format("Timed out acquiring case name lock for %s for %s", caseName, manifest.getFilePath()));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -46,18 +46,12 @@ final class PathUtils {
|
|||||||
* @return The path of the case folder, or null if it is not found.
|
* @return The path of the case folder, or null if it is not found.
|
||||||
*/
|
*/
|
||||||
static Path findCaseDirectory(Path folderToSearch, String caseName) {
|
static Path findCaseDirectory(Path folderToSearch, String caseName) {
|
||||||
String sanitizedCaseName;
|
|
||||||
try {
|
|
||||||
sanitizedCaseName = Case.displayNameToCaseName(caseName);
|
|
||||||
} catch (Case.IllegalCaseNameException unused) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
File searchFolder = new File(folderToSearch.toString());
|
File searchFolder = new File(folderToSearch.toString());
|
||||||
if (!searchFolder.isDirectory()) {
|
if (!searchFolder.isDirectory()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
Path caseFolderPath = null;
|
Path caseFolderPath = null;
|
||||||
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(sanitizedCaseName));
|
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(caseName));
|
||||||
long mostRecentModified = 0;
|
long mostRecentModified = 0;
|
||||||
for (String candidateFolder : candidateFolders) {
|
for (String candidateFolder : candidateFolders) {
|
||||||
File file = new File(candidateFolder);
|
File file = new File(candidateFolder);
|
||||||
|
159
ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java
Executable file
159
ImageGallery/src/org/sleuthkit/autopsy/imagegallery/actions/DeleteTagAction.java
Executable file
@ -0,0 +1,159 @@
|
|||||||
|
/*
|
||||||
|
* 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.imagegallery.actions;
|
||||||
|
|
||||||
|
import java.awt.Window;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.concurrent.ExecutionException;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javafx.application.Platform;
|
||||||
|
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.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;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to remove tags from content.
|
||||||
|
*/
|
||||||
|
public class DeleteTagAction extends Action {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(DeleteTagAction.class.getName());
|
||||||
|
|
||||||
|
private final ImageGalleryController controller;
|
||||||
|
private final long fileId;
|
||||||
|
private final TagName tagName;
|
||||||
|
private final ContentTag contentTag;
|
||||||
|
|
||||||
|
public DeleteTagAction(ImageGalleryController controller, TagName tagName, ContentTag contentTag, long fileId) {
|
||||||
|
super(tagName.getDisplayName());
|
||||||
|
this.controller = controller;
|
||||||
|
this.fileId = fileId;
|
||||||
|
this.tagName = tagName;
|
||||||
|
this.contentTag = contentTag;
|
||||||
|
setGraphic(controller.getTagsManager().getGraphic(tagName));
|
||||||
|
setText(tagName.getDisplayName());
|
||||||
|
setEventHandler(actionEvent -> deleteTag());
|
||||||
|
}
|
||||||
|
|
||||||
|
static public Menu getTagMenu(ImageGalleryController controller) {
|
||||||
|
return new TagMenu(controller);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"# {0} - fileID",
|
||||||
|
"DeleteDrawableTagAction.deleteTag.alert=Unable to untag file {0}."})
|
||||||
|
private void deleteTag() {
|
||||||
|
new SwingWorker<Void, Void>() {
|
||||||
|
|
||||||
|
@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));
|
||||||
|
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()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void done() {
|
||||||
|
super.done();
|
||||||
|
try {
|
||||||
|
get();
|
||||||
|
} catch (InterruptedException | ExecutionException ex) {
|
||||||
|
LOGGER.log(Level.SEVERE, "Unexpected exception while untagging file", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}.execute();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NbBundle.Messages({"DeleteDrawableTagAction.displayName=Remove File Tag"})
|
||||||
|
private static class TagMenu extends Menu {
|
||||||
|
|
||||||
|
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));
|
||||||
|
AbstractFile file = selectedFilesList.iterator().next();
|
||||||
|
|
||||||
|
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++) {
|
||||||
|
TagName tagName = tagNameIterator.next();
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagMenu.class.getName())
|
||||||
|
.log(Level.SEVERE, "Error retrieving tags for TagMenu", ex); //NON-NLS
|
||||||
|
}
|
||||||
|
|
||||||
|
if(getItems().isEmpty()) {
|
||||||
|
setDisable(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2013-16 Basis Technology Corp.
|
* Copyright 2013-2017 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
|
|||||||
import com.google.common.eventbus.Subscribe;
|
import com.google.common.eventbus.Subscribe;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Collection;
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javafx.application.Platform;
|
import javafx.application.Platform;
|
||||||
@ -49,6 +50,7 @@ import javax.swing.SwingUtilities;
|
|||||||
import org.controlsfx.control.action.ActionUtils;
|
import org.controlsfx.control.action.ActionUtils;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.openide.util.actions.Presenter;
|
import org.openide.util.actions.Presenter;
|
||||||
import org.openide.windows.TopComponent;
|
import org.openide.windows.TopComponent;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
@ -66,10 +68,12 @@ import org.sleuthkit.autopsy.imagegallery.ImageGalleryTopComponent;
|
|||||||
import org.sleuthkit.autopsy.imagegallery.actions.AddTagAction;
|
import org.sleuthkit.autopsy.imagegallery.actions.AddTagAction;
|
||||||
import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction;
|
import org.sleuthkit.autopsy.imagegallery.actions.CategorizeAction;
|
||||||
import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction;
|
import org.sleuthkit.autopsy.imagegallery.actions.DeleteFollowUpTagAction;
|
||||||
|
import org.sleuthkit.autopsy.imagegallery.actions.DeleteTagAction;
|
||||||
import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction;
|
import org.sleuthkit.autopsy.imagegallery.actions.OpenExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter;
|
import org.sleuthkit.autopsy.imagegallery.actions.SwingMenuItemAdapter;
|
||||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
|
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
|
||||||
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.ContentTag;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.TagName;
|
import org.sleuthkit.datamodel.TagName;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
@ -184,6 +188,11 @@ public abstract class DrawableTileBase extends DrawableUIBase {
|
|||||||
|
|
||||||
menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
|
menuItems.add(CategorizeAction.getCategoriesMenu(getController()));
|
||||||
menuItems.add(AddTagAction.getTagMenu(getController()));
|
menuItems.add(AddTagAction.getTagMenu(getController()));
|
||||||
|
|
||||||
|
final Collection<AbstractFile> selectedFilesList = new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
menuItems.add(DeleteTagAction.getTagMenu(getController()));
|
||||||
|
}
|
||||||
|
|
||||||
final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles());
|
final MenuItem extractMenuItem = new MenuItem(Bundle.DrawableTileBase_menuItem_extractFiles());
|
||||||
extractMenuItem.setOnAction(actionEvent -> {
|
extractMenuItem.setOnAction(actionEvent -> {
|
||||||
|
120
InternalPythonModules/android/browserlocation.py
Normal file
120
InternalPythonModules/android/browserlocation.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.lang import Double
|
||||||
|
from java.lang import Long
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Analyzes database created by browser that stores GEO location info.
|
||||||
|
"""
|
||||||
|
class BrowserLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
abstractFiles = fileManager.findFiles(dataSource, "CachedGeoposition%.db")
|
||||||
|
for abstractFile in abstractFiles:
|
||||||
|
if abstractFile.getSize() == 0:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findGeoLocationsInDB(jFile.toString(), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing browser location files", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding browser location files", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findGeoLocationsInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC") #load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error connecting to SQL database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery("SELECT timestamp, latitude, longitude, accuracy FROM CachedPosition;")
|
||||||
|
while resultSet.next():
|
||||||
|
timestamp = Long.valueOf(resultSet.getString("timestamp")) / 1000
|
||||||
|
latitude = Double.valueOf(resultSet.getString("latitude"))
|
||||||
|
longitude = Double.valueOf(resultSet.getString("longitude"))
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, general.MODULE_NAME, latitude))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, general.MODULE_NAME, longitude))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, timestamp))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Browser Location History"))
|
||||||
|
# artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(),moduleName, accuracy))
|
||||||
|
# NOTE: originally commented out
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactTypeName(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error putting artifacts to blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
147
InternalPythonModules/android/cachelocation.py
Normal file
147
InternalPythonModules/android/cachelocation.py
Normal file
@ -0,0 +1,147 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.io import FileInputStream
|
||||||
|
from java.io import InputStream
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.math import BigInteger
|
||||||
|
from java.nio import ByteBuffer
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Parses cache files that Android maintains for Wifi and cell towers. Adds GPS points to blackboard.
|
||||||
|
"""
|
||||||
|
class CacheLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
"""
|
||||||
|
cache.cell stores mobile tower GPS locations and cache.wifi stores GPS
|
||||||
|
and MAC info from Wifi points.
|
||||||
|
"""
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
abstractFiles = fileManager.findFiles(dataSource, "cache.cell")
|
||||||
|
abstractFiles.addAll(fileManager.findFiles(dataSource, "cache.wifi"))
|
||||||
|
for abstractFile in abstractFiles:
|
||||||
|
if abstractFile.getSize() == 0:
|
||||||
|
continue
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findGeoLocationsInFile(jFile, abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing cached location files", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding cached location files", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findGeoLocationsInFile(self, file, abstractFile):
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 2) # will temporarily hold bytes to be converted into the correct data types
|
||||||
|
|
||||||
|
try:
|
||||||
|
inputStream = FileInputStream(file)
|
||||||
|
|
||||||
|
inputStream.read(tempBytes) # version
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 2)
|
||||||
|
inputStream.read(tempBytes) # number of location entries
|
||||||
|
|
||||||
|
iterations = BigInteger(tempBytes).intValue()
|
||||||
|
|
||||||
|
for i in range(iterations): # loop through every entry
|
||||||
|
tempBytes = bytearray([0] * 2)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
|
||||||
|
tempBytes = bytearray([0])
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
|
||||||
|
while BigInteger(tempBytes).intValue() != 0: # pass through non important values until the start of accuracy(around 7-10 bytes)
|
||||||
|
if 0 > inputStream.read(tempBytes):
|
||||||
|
break # we've passed the end of the file, so stop
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 3)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
if BigInteger(tempBytes).intValue() <= 0: # This refers to a location that could not be calculated
|
||||||
|
tempBytes = bytearray([0] * 28) # read rest of the row's bytes
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
continue
|
||||||
|
accuracy = "" + BigInteger(tempBytes).intValue()
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 4)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
confidence = "" + BigInteger(tempBytes).intValue()
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 8)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
latitude = CacheLocationAnalyzer.toDouble(bytes)
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 8)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
longitude = CacheLocationAnalyzer.toDouble(bytes)
|
||||||
|
|
||||||
|
tempBytes = bytearray([0] * 8)
|
||||||
|
inputStream.read(tempBytes)
|
||||||
|
timestamp = BigInteger(tempBytes).longValue() / 1000
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_TRACKPOINT)
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE, AndroidAnalyzer.MODULE_NAME, latitude))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE, AndroidAnalyzer.MODULE_NAME, longitude))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, AndroidModuleFactorymodule.Name, timestamp))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, AndroidAnalyzer.MODULE_NAME,
|
||||||
|
file.getName() + "Location History"))
|
||||||
|
|
||||||
|
#Not storing these for now.
|
||||||
|
# artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_VALUE.getTypeID(), AndroidModuleFactorymodule.moduleName, accuracy))
|
||||||
|
# artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(), AndroidModuleFactorymodule.moduleName, confidence))
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index GPS trackpoint artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Cached GPS locations to blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def toDouble(byteArray):
|
||||||
|
return ByteBuffer.wrap(byteArray).getDouble()
|
155
InternalPythonModules/android/calllog.py
Normal file
155
InternalPythonModules/android/calllog.py
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.io import IOException
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.lang import String
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||||
|
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel.BlackboardAttribute import ATTRIBUTE_TYPE
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Locates a variety of different call log databases, parses them, and populates the blackboard.
|
||||||
|
"""
|
||||||
|
class CallLogAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
# the names of tables that potentially hold call logs in the dbs
|
||||||
|
_tableNames = ["calls", "logs"]
|
||||||
|
|
||||||
|
class CallDirection:
|
||||||
|
|
||||||
|
def __init__(self, type, displayName):
|
||||||
|
self.type = type
|
||||||
|
self.displayName = displayName
|
||||||
|
|
||||||
|
def getDisplayName(self):
|
||||||
|
return self.displayName
|
||||||
|
|
||||||
|
INCOMING = CallDirection(1, "Incoming")
|
||||||
|
OUTGOING = CallDirection(2, "Outgoing")
|
||||||
|
MISSED = CallDirection(3, "Missed")
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def fromType(t):
|
||||||
|
return {
|
||||||
|
1: CallLogAnalyzer.INCOMING,
|
||||||
|
2: CallLogAnalyzer.OUTGOING,
|
||||||
|
3: CallLogAnalyzer.MISSED
|
||||||
|
}.get(t, None)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "logs.db")
|
||||||
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts.db"))
|
||||||
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
file = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, file, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findCallLogsInDB(file.toString(), abstractFile)
|
||||||
|
except IOException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error writing temporary call log db to disk", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding call logs", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findCallLogsInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
bbartifacts = list()
|
||||||
|
try:
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
|
||||||
|
|
||||||
|
for tableName in CallLogAnalyzer._tableNames:
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery("SELECT number, date, duration, type, name FROM " + tableName + " ORDER BY date DESC;")
|
||||||
|
self._logger.log(Level.INFO, "Reading call log from table {0} in db {1}", [tableName, databasePath])
|
||||||
|
while resultSet.next():
|
||||||
|
date = resultSet.getLong("date") / 1000
|
||||||
|
direction = CallLogAnalyzer.fromType(resultSet.getInt("type"))
|
||||||
|
directionString = direction.getDisplayName() if direction is not None else ""
|
||||||
|
number = resultSet.getString("number")
|
||||||
|
duration = resultSet.getLong("duration") # duration of call is in seconds
|
||||||
|
name = resultSet.getString("name") # name of person dialed or called. None if unregistered
|
||||||
|
|
||||||
|
try:
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG) # create a call log and then add attributes from result set.
|
||||||
|
if direction == CallLogAnalyzer.OUTGOING:
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, number))
|
||||||
|
else: # Covers INCOMING and MISSED
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, number))
|
||||||
|
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_START, general.MODULE_NAME, date))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DATETIME_END, general.MODULE_NAME, duration + date))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, directionString))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||||
|
|
||||||
|
bbartifacts.append(artifact)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index call log artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error posting call log record to the blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except SQLException as ex:
|
||||||
|
self._logger.log(Level.WARNING, String.format("Could not read table %s in db %s", tableName, databasePath), ex)
|
||||||
|
except SQLException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Could not parse call log; error connecting to db " + databasePath, ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
if bbartifacts:
|
||||||
|
IngestServices.getInstance().fireModuleDataEvent(ModuleDataEvent(general.MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_CALLLOG, bbartifacts))
|
||||||
|
|
164
InternalPythonModules/android/contact.py
Normal file
164
InternalPythonModules/android/contact.py
Normal file
@ -0,0 +1,164 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DatabaseMetaData
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||||
|
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Locates a variety of different contacts databases, parses them, and populates the blackboard.
|
||||||
|
"""
|
||||||
|
class ContactAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "contacts.db")
|
||||||
|
absFiles.addAll(fileManager.findFiles(dataSource, "contacts2.db"))
|
||||||
|
if absFiles.isEmpty():
|
||||||
|
return
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findContactsInDB(str(jFile.toString()), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Contacts", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding Contacts", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
"""
|
||||||
|
Will create artifact from a database given by the path
|
||||||
|
The fileId will be the abstract file associated with the artifacts
|
||||||
|
"""
|
||||||
|
def __findContactsInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
bbartifacts = list()
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error opening database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
# get display_name, mimetype(email or phone number) and data1 (phonenumber or email address depending on mimetype)
|
||||||
|
# sorted by name, so phonenumber/email would be consecutive for a person if they exist.
|
||||||
|
# check if contacts.name_raw_contact_id exists. Modify the query accordingly.
|
||||||
|
columnFound = False
|
||||||
|
metadata = connection.getMetaData()
|
||||||
|
columnListResultSet = metadata.getColumns(None, None, "contacts", None)
|
||||||
|
while columnListResultSet.next():
|
||||||
|
if columnListResultSet.getString("COLUMN_NAME") == "name_raw_contact_id":
|
||||||
|
columnFound = True
|
||||||
|
break
|
||||||
|
if columnFound:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT mimetype, data1, name_raw_contact.display_name AS display_name \n"
|
||||||
|
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n"
|
||||||
|
+ "JOIN raw_contacts AS name_raw_contact ON(name_raw_contact_id=name_raw_contact._id) "
|
||||||
|
+ "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n"
|
||||||
|
+ "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n"
|
||||||
|
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n"
|
||||||
|
+ "ORDER BY name_raw_contact.display_name ASC;")
|
||||||
|
else:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT mimetype, data1, raw_contacts.display_name AS display_name \n"
|
||||||
|
+ "FROM raw_contacts JOIN contacts ON (raw_contacts.contact_id=contacts._id) \n"
|
||||||
|
+ "LEFT OUTER JOIN data ON (data.raw_contact_id=raw_contacts._id) \n"
|
||||||
|
+ "LEFT OUTER JOIN mimetypes ON (data.mimetype_id=mimetypes._id) \n"
|
||||||
|
+ "WHERE mimetype = 'vnd.android.cursor.item/phone_v2' OR mimetype = 'vnd.android.cursor.item/email_v2'\n"
|
||||||
|
+ "ORDER BY raw_contacts.display_name ASC;")
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||||
|
oldName = ""
|
||||||
|
while resultSet.next():
|
||||||
|
name = resultSet.getString("display_name")
|
||||||
|
data1 = resultSet.getString("data1") # the phone number or email
|
||||||
|
mimetype = resultSet.getString("mimetype") # either phone or email
|
||||||
|
if name != oldName:
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT)
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, name))
|
||||||
|
if mimetype == "vnd.android.cursor.item/phone_v2":
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER, general.MODULE_NAME, data1))
|
||||||
|
else:
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_EMAIL, general.MODULE_NAME, data1))
|
||||||
|
|
||||||
|
oldName = name
|
||||||
|
|
||||||
|
bbartifacts.append(artifact)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index contact artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except SQLException as ex:
|
||||||
|
self._logger.log(Level.WARNING, "Unable to execute contacts SQL query against {0} : {1}", [databasePath, ex])
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error posting to blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
if bbartifacts:
|
||||||
|
IngestServices.getInstance().fireModuleDataEvent(ModuleDataEvent(general.MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_CONTACT, bbartifacts))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
28
InternalPythonModules/android/general.py
Normal file
28
InternalPythonModules/android/general.py
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
MODULE_NAME = "Android Analyzer"
|
||||||
|
|
||||||
|
"""
|
||||||
|
A parent class of the analyzers
|
||||||
|
"""
|
||||||
|
class AndroidComponentAnalyzer:
|
||||||
|
# The Analyzer should implement this method
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
raise NotImplementedError
|
139
InternalPythonModules/android/googlemaplocation.py
Normal file
139
InternalPythonModules/android/googlemaplocation.py
Normal file
@ -0,0 +1,139 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.lang import Double
|
||||||
|
from java.lang import Long
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Finds and parses the Google Maps database.
|
||||||
|
"""
|
||||||
|
class GoogleMapLocationAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "da_destination_history")
|
||||||
|
if absFiles.isEmpty():
|
||||||
|
return
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findGeoLocationsInDB(jFile.toString(), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Google map locations", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding Google map locations", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findGeoLocationsInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error opening database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT time, dest_lat, dest_lng, dest_title, dest_address, source_lat, source_lng FROM destination_history;")
|
||||||
|
|
||||||
|
while resultSet.next():
|
||||||
|
time = Long.valueOf(resultSet.getString("time")) / 1000
|
||||||
|
dest_title = resultSet.getString("dest_title")
|
||||||
|
dest_address = resultSet.getString("dest_address")
|
||||||
|
|
||||||
|
dest_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("dest_lat"))
|
||||||
|
dest_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("dest_lng"))
|
||||||
|
source_lat = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lat"))
|
||||||
|
source_lng = GoogleMapLocationAnalyzer.convertGeo(resultSet.getString("source_lng"))
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_GPS_ROUTE)
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_CATEGORY, general.MODULE_NAME, "Destination"))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, time))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_END, general.MODULE_NAME, dest_lat))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_END, general.MODULE_NAME, dest_lng))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LATITUDE_START, general.MODULE_NAME, source_lat))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_GEO_LONGITUDE_START, general.MODULE_NAME, source_lng))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, dest_title))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_LOCATION, general.MODULE_NAME, dest_address))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PROG_NAME, general.MODULE_NAME, "Google Maps History"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index GPS route artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Google map locations to the blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing the database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
# add periods 6 decimal places before the end.
|
||||||
|
@staticmethod
|
||||||
|
def convertGeo(s):
|
||||||
|
length = len(s)
|
||||||
|
if length > 6:
|
||||||
|
return Double.valueOf(s[0 : length-6] + "." + s[length-6 : length])
|
||||||
|
else:
|
||||||
|
return Double.valueOf(s)
|
126
InternalPythonModules/android/module.py
Normal file
126
InternalPythonModules/android/module.py
Normal file
@ -0,0 +1,126 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import jarray
|
||||||
|
import inspect
|
||||||
|
import traceback
|
||||||
|
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Version
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestModuleFactory
|
||||||
|
from org.sleuthkit.autopsy.ingest import DataSourceIngestModule
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestModuleFactoryAdapter
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestModuleIngestJobSettings
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.ingest import DataSourceIngestModuleProgress
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestModule
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.autopsy.ingest import DataSourceIngestModule
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestMessage
|
||||||
|
|
||||||
|
import general
|
||||||
|
import browserlocation
|
||||||
|
import cachelocation
|
||||||
|
import calllog
|
||||||
|
import contact
|
||||||
|
import googlemaplocation
|
||||||
|
import tangomessage
|
||||||
|
import textmessage
|
||||||
|
import wwfmessage
|
||||||
|
|
||||||
|
class AndroidModuleFactory(IngestModuleFactoryAdapter):
|
||||||
|
|
||||||
|
moduleName = general.MODULE_NAME
|
||||||
|
|
||||||
|
def getModuleDisplayName(self):
|
||||||
|
return self.moduleName
|
||||||
|
|
||||||
|
def getModuleDescription(self):
|
||||||
|
return "Extracts Android system and third-party app data."
|
||||||
|
|
||||||
|
def getModuleVersionNumber(self):
|
||||||
|
return Version.getVersion()
|
||||||
|
|
||||||
|
def isDataSourceIngestModuleFactory(self):
|
||||||
|
return True
|
||||||
|
|
||||||
|
def createDataSourceIngestModule(self, ingestOptions):
|
||||||
|
return AndroidIngestModule()
|
||||||
|
|
||||||
|
|
||||||
|
class AndroidIngestModule(DataSourceIngestModule):
|
||||||
|
|
||||||
|
_logger = Logger.getLogger(AndroidModuleFactory.moduleName)
|
||||||
|
|
||||||
|
def log(self, level, msg):
|
||||||
|
self._logger.logp(level, self.__class__.__name__, inspect.stack()[1][3], msg)
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.context = None
|
||||||
|
|
||||||
|
def startUp(self, context):
|
||||||
|
self.context = context
|
||||||
|
|
||||||
|
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
|
||||||
|
|
||||||
|
# Where the analysis is done.
|
||||||
|
def process(self, dataSource, progressBar):
|
||||||
|
|
||||||
|
errors = []
|
||||||
|
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
||||||
|
analyzers = [contact.ContactAnalyzer(), calllog.CallLogAnalyzer(), textmessage.TextMessageAnalyzer(), tangomessage.TangoMessageAnalyzer(), wwfmessage.WWFMessageAnalyzer(), googlemaplocation.GoogleMapLocationAnalyzer(), browserlocation.BrowserLocationAnalyzer(), cachelocation.CacheLocationAnalyzer()]
|
||||||
|
self.log(Level.INFO, "running " + str(len(analyzers)) + " analyzers")
|
||||||
|
progressBar.switchToDeterminate(len(analyzers))
|
||||||
|
|
||||||
|
n = 0
|
||||||
|
for analyzer in analyzers:
|
||||||
|
if self.context.dataSourceIngestIsCancelled():
|
||||||
|
return IngestModule.ProcessResult.OK
|
||||||
|
try:
|
||||||
|
analyzer.analyze(dataSource, fileManager, self.context)
|
||||||
|
n += 1
|
||||||
|
progressBar.progress(n)
|
||||||
|
except Exception as ex:
|
||||||
|
errors.append("Error running " + analyzer.__class__.__name__)
|
||||||
|
self.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
errorMessage = [] # NOTE: this isn't used?
|
||||||
|
errorMessageSubject = "" # NOTE: this isn't used?
|
||||||
|
msgLevel = IngestMessage.MessageType.INFO
|
||||||
|
|
||||||
|
if errors:
|
||||||
|
msgLevel = IngestMessage.MessageType.ERROR
|
||||||
|
errorMessage.append("Errors were encountered")
|
||||||
|
|
||||||
|
errorMessage.append("<ul>") # NOTE: this was missing in the original java code
|
||||||
|
for msg in errors:
|
||||||
|
errorMessage.extend(["<li>", msg, "</li>\n"])
|
||||||
|
errorMessage.append("</ul>\n")
|
||||||
|
|
||||||
|
if len(errors) == 1:
|
||||||
|
errorMsgSubject = "One error was found"
|
||||||
|
else:
|
||||||
|
errorMsgSubject = "errors found: " + str(len(errors))
|
||||||
|
else:
|
||||||
|
errorMessage.append("No errors")
|
||||||
|
errorMsgSubject = "No errors"
|
||||||
|
|
||||||
|
return IngestModule.ProcessResult.OK
|
136
InternalPythonModules/android/tangomessage.py
Normal file
136
InternalPythonModules/android/tangomessage.py
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.lang import Long
|
||||||
|
from java.lang import String
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.apache.commons.codec.binary import Base64
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Locates database for the Tango app and adds info to blackboard.
|
||||||
|
"""
|
||||||
|
class TangoMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "tc.db")
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findTangoMessagesInDB(jFile.toString(), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Tango messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding Tango messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findTangoMessagesInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error opening database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT conv_id, create_time, direction, payload FROM messages ORDER BY create_time DESC;")
|
||||||
|
|
||||||
|
while resultSet.next():
|
||||||
|
conv_id = resultSet.getString("conv_id") # seems to wrap around the message found in payload after decoding from base-64
|
||||||
|
create_time = Long.valueOf(resultSet.getString("create_time")) / 1000
|
||||||
|
if resultSet.getString("direction") == "1": # 1 incoming, 2 outgoing
|
||||||
|
direction = "Incoming"
|
||||||
|
else:
|
||||||
|
direction = "Outgoing"
|
||||||
|
payload = resultSet.getString("payload")
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) #create a call log and then add attributes from result set.
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, create_time))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, direction))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, TangoMessageAnalyzer.decodeMessage(conv_id, payload)))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Tango Message"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index Tango message artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing Tango messages to the blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
# take the message string which is wrapped by a certain string, and return the text enclosed.
|
||||||
|
@staticmethod
|
||||||
|
def decodeMessage(wrapper, message):
|
||||||
|
result = ""
|
||||||
|
decoded = Base64.decodeBase64(message)
|
||||||
|
try:
|
||||||
|
Z = String(decoded, "UTF-8")
|
||||||
|
result = Z.split(wrapper)[1]
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error decoding a Tango message", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return result
|
132
InternalPythonModules/android/textmessage.py
Normal file
132
InternalPythonModules/android/textmessage.py
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.lang import Integer
|
||||||
|
from java.lang import Long
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestServices
|
||||||
|
from org.sleuthkit.autopsy.ingest import ModuleDataEvent
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Finds database with SMS/MMS messages and adds them to blackboard.
|
||||||
|
"""
|
||||||
|
class TextMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "mmssms.db")
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findTextsInDB(jFile.toString(), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing text messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding text messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findTextsInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
bbartifacts = list()
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC") # load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error opening database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT address, date, read, type, subject, body FROM sms;")
|
||||||
|
while resultSet.next():
|
||||||
|
address = resultSet.getString("address") # may be phone number, or other addresses
|
||||||
|
date = Long.valueOf(resultSet.getString("date")) / 1000
|
||||||
|
read = resultSet.getInt("read") # may be unread = 0, read = 1
|
||||||
|
subject = resultSet.getString("subject") # message subject
|
||||||
|
body = resultSet.getString("body") # message body
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE); #create Message artifact and then add attributes from result set.
|
||||||
|
if resultSet.getString("type") == "1":
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Incoming"))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_FROM, general.MODULE_NAME, address))
|
||||||
|
else:
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DIRECTION, general.MODULE_NAME, "Outgoing"))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO, general.MODULE_NAME, address))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, date))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_READ_STATUS, general.MODULE_NAME, Integer(read)))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT, general.MODULE_NAME, subject))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, body))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "SMS Message"))
|
||||||
|
|
||||||
|
bbartifacts.append(artifact)
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index text message artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing text messages to blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
if bbartifacts:
|
||||||
|
IngestServices.getInstance().fireModuleDataEvent(ModuleDataEvent(general.MODULE_NAME, BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE, bbartifacts))
|
||||||
|
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
118
InternalPythonModules/android/wwfmessage.py
Normal file
118
InternalPythonModules/android/wwfmessage.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
"""
|
||||||
|
Autopsy Forensic Browser
|
||||||
|
|
||||||
|
Copyright 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.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from java.io import File
|
||||||
|
from java.lang import Class
|
||||||
|
from java.lang import ClassNotFoundException
|
||||||
|
from java.sql import Connection
|
||||||
|
from java.sql import DriverManager
|
||||||
|
from java.sql import ResultSet
|
||||||
|
from java.sql import SQLException
|
||||||
|
from java.sql import Statement
|
||||||
|
from java.util.logging import Level
|
||||||
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
|
from org.sleuthkit.autopsy.coreutils import Logger
|
||||||
|
from org.sleuthkit.autopsy.coreutils import MessageNotifyUtil
|
||||||
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
|
from org.sleuthkit.autopsy.ingest import IngestJobContext
|
||||||
|
from org.sleuthkit.datamodel import AbstractFile
|
||||||
|
from org.sleuthkit.datamodel import BlackboardArtifact
|
||||||
|
from org.sleuthkit.datamodel import BlackboardAttribute
|
||||||
|
from org.sleuthkit.datamodel import Content
|
||||||
|
from org.sleuthkit.datamodel import TskCoreException
|
||||||
|
|
||||||
|
import traceback
|
||||||
|
import general
|
||||||
|
|
||||||
|
"""
|
||||||
|
Analyzes messages from Words With Friends
|
||||||
|
"""
|
||||||
|
class WWFMessageAnalyzer(general.AndroidComponentAnalyzer):
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self._logger = Logger.getLogger(self.__class__.__name__)
|
||||||
|
|
||||||
|
def analyze(self, dataSource, fileManager, context):
|
||||||
|
try:
|
||||||
|
absFiles = fileManager.findFiles(dataSource, "WordsFramework")
|
||||||
|
for abstractFile in absFiles:
|
||||||
|
try:
|
||||||
|
jFile = File(Case.getCurrentCase().getTempDirectory(), str(abstractFile.getId()) + abstractFile.getName())
|
||||||
|
ContentUtils.writeToFile(abstractFile, jFile, context.dataSourceIngestIsCancelled)
|
||||||
|
self.__findWWFMessagesInDB(jFile.toString(), abstractFile)
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing WWF messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
except TskCoreException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error finding WWF messages", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
|
||||||
|
def __findWWFMessagesInDB(self, databasePath, abstractFile):
|
||||||
|
if not databasePath:
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
Class.forName("org.sqlite.JDBC"); # load JDBC driver
|
||||||
|
connection = DriverManager.getConnection("jdbc:sqlite:" + databasePath)
|
||||||
|
statement = connection.createStatement()
|
||||||
|
except (ClassNotFoundException, SQLException) as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error opening database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
return
|
||||||
|
|
||||||
|
try:
|
||||||
|
resultSet = statement.executeQuery(
|
||||||
|
"SELECT message, strftime('%s' ,created_at) as datetime, user_id, game_id FROM chat_messages ORDER BY game_id DESC, created_at DESC;")
|
||||||
|
|
||||||
|
while resultSet.next():
|
||||||
|
message = resultSet.getString("message") # WWF Message
|
||||||
|
created_at = resultSet.getLong("datetime")
|
||||||
|
user_id = resultSet.getString("user_id") # the ID of the user who sent the message.
|
||||||
|
game_id = resultSet.getString("game_id") # ID of the game which the the message was sent.
|
||||||
|
|
||||||
|
artifact = abstractFile.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE) # create a call log and then add attributes from result set.
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_DATETIME, general.MODULE_NAME, created_at))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_NAME, general.MODULE_NAME, user_id))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MSG_ID, general.MODULE_NAME, game_id))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT, general.MODULE_NAME, message))
|
||||||
|
artifact.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_MESSAGE_TYPE, general.MODULE_NAME, "Words With Friends Message"))
|
||||||
|
|
||||||
|
try:
|
||||||
|
# index the artifact for keyword search
|
||||||
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
blackboard.indexArtifact(artifact)
|
||||||
|
except Blackboard.BlackboardException as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Unable to index blackboard artifact " + artifact.getArtifactID(), ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
MessageNotifyUtil.Notify.error("Failed to index WWF message artifact for keyword search.", artifact.getDisplayName())
|
||||||
|
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error parsing WWF messages to the blackboard", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
||||||
|
finally:
|
||||||
|
try:
|
||||||
|
if resultSet is not None:
|
||||||
|
resultSet.close()
|
||||||
|
statement.close()
|
||||||
|
connection.close()
|
||||||
|
except Exception as ex:
|
||||||
|
self._logger.log(Level.SEVERE, "Error closing database", ex)
|
||||||
|
self._logger.log(Level.SEVERE, traceback.format_exc())
|
@ -19,6 +19,8 @@
|
|||||||
package org.sleuthkit.autopsy.keywordsearch;
|
package org.sleuthkit.autopsy.keywordsearch;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.FilterNode;
|
import org.openide.nodes.FilterNode;
|
||||||
@ -26,14 +28,17 @@ import org.openide.nodes.Node;
|
|||||||
import org.openide.nodes.Node.Property;
|
import org.openide.nodes.Node.Property;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.openide.util.lookup.ProxyLookup;
|
import org.openide.util.lookup.ProxyLookup;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.ContentVisitor;
|
import org.sleuthkit.datamodel.ContentVisitor;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
@ -107,16 +112,23 @@ class KeywordSearchFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private List<Action> getFileActions() {
|
private List<Action> getFileActions() {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actionsList = new ArrayList<>();
|
||||||
actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this));
|
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this));
|
||||||
actions.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
|
||||||
actions.add(null);
|
actionsList.add(null);
|
||||||
actions.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actions.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal()));
|
actionsList.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal()));
|
||||||
actions.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actions.add(AddContentTagAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
|
||||||
return actions;
|
final Collection<AbstractFile> selectedFilesList =
|
||||||
|
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if(selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actionsList;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -4,7 +4,7 @@ app.title=Autopsy
|
|||||||
### lowercase version of above
|
### lowercase version of above
|
||||||
app.name=${branding.token}
|
app.name=${branding.token}
|
||||||
### if left unset, version will default to today's date
|
### if left unset, version will default to today's date
|
||||||
app.version=4.3.0
|
app.version=4.4.0
|
||||||
### build.type must be one of: DEVELOPMENT, RELEASE
|
### build.type must be one of: DEVELOPMENT, RELEASE
|
||||||
#build.type=RELEASE
|
#build.type=RELEASE
|
||||||
build.type=DEVELOPMENT
|
build.type=DEVELOPMENT
|
||||||
|
@ -58,8 +58,7 @@ from org.sleuthkit.autopsy.casemodule import Case
|
|||||||
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
from org.sleuthkit.autopsy.datamodel import ContentUtils
|
||||||
from org.sleuthkit.autopsy.casemodule.services import Services
|
from org.sleuthkit.autopsy.casemodule.services import Services
|
||||||
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
# This will work in 4.0.1 and beyond
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
# from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@ -98,25 +97,22 @@ class ContactsDbIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
# Where any setup and configuration is done
|
# Where any setup and configuration is done
|
||||||
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
||||||
def startUp(self, context):
|
def startUp(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
|
|
||||||
# raise IngestModuleException("Oh No!")
|
|
||||||
|
|
||||||
# Where the analysis is done.
|
# Where the analysis is done.
|
||||||
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
||||||
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.3/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.4/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
||||||
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
||||||
def process(self, dataSource, progressBar):
|
def process(self, dataSource, progressBar):
|
||||||
|
|
||||||
# we don't know how much work there is yet
|
# we don't know how much work there is yet
|
||||||
progressBar.switchToIndeterminate()
|
progressBar.switchToIndeterminate()
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
|
||||||
# Use blackboard class to index blackboard artifacts for keyword search
|
# Use blackboard class to index blackboard artifacts for keyword search
|
||||||
# blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
|
||||||
# Find files named contacts.db, regardless of parent path
|
# Find files named contacts.db, regardless of parent path
|
||||||
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
||||||
@ -124,7 +120,7 @@ class ContactsDbIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
numFiles = len(files)
|
numFiles = len(files)
|
||||||
progressBar.switchToDeterminate(numFiles)
|
progressBar.switchToDeterminate(numFiles)
|
||||||
fileCount = 0;
|
fileCount = 0
|
||||||
for file in files:
|
for file in files:
|
||||||
|
|
||||||
# Check if the user pressed cancel while we were busy
|
# Check if the user pressed cancel while we were busy
|
||||||
@ -176,12 +172,12 @@ class ContactsDbIngestModule(DataSourceIngestModule):
|
|||||||
art.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(),
|
art.addAttribute(BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER.getTypeID(),
|
||||||
ContactsDbIngestModuleFactory.moduleName, phone))
|
ContactsDbIngestModuleFactory.moduleName, phone))
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
|
||||||
#try:
|
try:
|
||||||
# # index the artifact for keyword search
|
# index the artifact for keyword search
|
||||||
# blackboard.indexArtifact(art)
|
blackboard.indexArtifact(art)
|
||||||
#except Blackboard.BlackboardException as e:
|
except Blackboard.BlackboardException as e:
|
||||||
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
||||||
|
|
||||||
# Fire an event to notify the UI and others that there are new artifacts
|
# Fire an event to notify the UI and others that there are new artifacts
|
||||||
IngestServices.getInstance().fireModuleDataEvent(
|
IngestServices.getInstance().fireModuleDataEvent(
|
||||||
|
@ -95,7 +95,7 @@ class RunExeIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
# Where any setup and configuration is done
|
# Where any setup and configuration is done
|
||||||
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
||||||
def startUp(self, context):
|
def startUp(self, context):
|
||||||
self.context = context
|
self.context = context
|
||||||
|
|
||||||
@ -108,9 +108,9 @@ class RunExeIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
# Where the analysis is done.
|
# Where the analysis is done.
|
||||||
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
||||||
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.3/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.4/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
||||||
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
||||||
def process(self, dataSource, progressBar):
|
def process(self, dataSource, progressBar):
|
||||||
|
|
||||||
# we don't know how much work there will be
|
# we don't know how much work there will be
|
||||||
|
@ -56,8 +56,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
|
|||||||
from org.sleuthkit.autopsy.casemodule import Case
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
from org.sleuthkit.autopsy.casemodule.services import Services
|
from org.sleuthkit.autopsy.casemodule.services import Services
|
||||||
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
# This will work in 4.0.1 and beyond
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
# from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
|
||||||
|
|
||||||
# Factory that defines the name and details of the module and allows Autopsy
|
# Factory that defines the name and details of the module and allows Autopsy
|
||||||
# to create instances of the modules that will do the anlaysis.
|
# to create instances of the modules that will do the anlaysis.
|
||||||
@ -93,7 +92,7 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
|
|||||||
|
|
||||||
# Where any setup and configuration is done
|
# Where any setup and configuration is done
|
||||||
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
||||||
# TODO: Add any setup code that you need here.
|
# TODO: Add any setup code that you need here.
|
||||||
def startUp(self, context):
|
def startUp(self, context):
|
||||||
self.filesFound = 0
|
self.filesFound = 0
|
||||||
@ -104,12 +103,11 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
|
|||||||
|
|
||||||
# Where the analysis is done. Each file will be passed into here.
|
# Where the analysis is done. Each file will be passed into here.
|
||||||
# The 'file' object being passed in is of type org.sleuthkit.datamodel.AbstractFile.
|
# The 'file' object being passed in is of type org.sleuthkit.datamodel.AbstractFile.
|
||||||
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.3/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html
|
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.4/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html
|
||||||
def process(self, file):
|
def process(self, file):
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
|
||||||
# Use blackboard class to index blackboard artifacts for keyword search
|
# Use blackboard class to index blackboard artifacts for keyword search
|
||||||
# blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
|
||||||
# Skip non-files
|
# Skip non-files
|
||||||
if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or
|
if ((file.getType() == TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS) or
|
||||||
@ -127,21 +125,20 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
|
|||||||
FindBigRoundFilesIngestModuleFactory.moduleName, "Big and Round Files")
|
FindBigRoundFilesIngestModuleFactory.moduleName, "Big and Round Files")
|
||||||
art.addAttribute(att)
|
art.addAttribute(att)
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
try:
|
||||||
#try:
|
# index the artifact for keyword search
|
||||||
# # index the artifact for keyword search
|
blackboard.indexArtifact(art)
|
||||||
# blackboard.indexArtifact(art)
|
except Blackboard.BlackboardException as e:
|
||||||
#except Blackboard.BlackboardException as e:
|
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
||||||
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
|
||||||
|
|
||||||
# Fire an event to notify the UI and others that there is a new artifact
|
# Fire an event to notify the UI and others that there is a new artifact
|
||||||
IngestServices.getInstance().fireModuleDataEvent(
|
IngestServices.getInstance().fireModuleDataEvent(
|
||||||
ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName,
|
ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName,
|
||||||
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None));
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None))
|
||||||
|
|
||||||
return IngestModule.ProcessResult.OK
|
return IngestModule.ProcessResult.OK
|
||||||
|
|
||||||
# Where any shutdown code is run and resources are freed.
|
# Where any shutdown code is run and resources are freed.
|
||||||
# TODO: Add any shutdown code that you need here.
|
# TODO: Add any shutdown code that you need here.
|
||||||
def shutDown(self):
|
def shutDown(self):
|
||||||
None
|
None
|
@ -27,7 +27,7 @@
|
|||||||
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
||||||
# OTHER DEALINGS IN THE SOFTWARE.
|
# OTHER DEALINGS IN THE SOFTWARE.
|
||||||
|
|
||||||
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
|
# See http://sleuthkit.org/autopsy/docs/api-docs/4.4/index.html for documentation
|
||||||
|
|
||||||
# Simple report module for Autopsy.
|
# Simple report module for Autopsy.
|
||||||
# Used as part of Python tutorials from Basis Technology - September 2015
|
# Used as part of Python tutorials from Basis Technology - September 2015
|
||||||
@ -71,7 +71,7 @@ class CSVReportModule(GeneralReportModuleAdapter):
|
|||||||
# TODO: Update this method to make a report
|
# TODO: Update this method to make a report
|
||||||
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath().
|
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath().
|
||||||
# The 'progressBar' object is of type ReportProgressPanel.
|
# The 'progressBar' object is of type ReportProgressPanel.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
|
||||||
def generateReport(self, baseReportDir, progressBar):
|
def generateReport(self, baseReportDir, progressBar):
|
||||||
|
|
||||||
# Open the output file.
|
# Open the output file.
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
# Simple data source-level ingest module for Autopsy.
|
# Simple data source-level ingest module for Autopsy.
|
||||||
# Search for TODO for the things that you need to change
|
# Search for TODO for the things that you need to change
|
||||||
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
|
# See http://sleuthkit.org/autopsy/docs/api-docs/4.4/index.html for documentation
|
||||||
|
|
||||||
import jarray
|
import jarray
|
||||||
import inspect
|
import inspect
|
||||||
@ -51,8 +51,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
|
|||||||
from org.sleuthkit.autopsy.casemodule import Case
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
from org.sleuthkit.autopsy.casemodule.services import Services
|
from org.sleuthkit.autopsy.casemodule.services import Services
|
||||||
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
# This will work in 4.0.1 and beyond
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
# from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
|
||||||
|
|
||||||
|
|
||||||
# Factory that defines the name and details of the module and allows Autopsy
|
# Factory that defines the name and details of the module and allows Autopsy
|
||||||
@ -95,32 +94,32 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
|
|||||||
|
|
||||||
# Where any setup and configuration is done
|
# Where any setup and configuration is done
|
||||||
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
||||||
# TODO: Add any setup code that you need here.
|
# TODO: Add any setup code that you need here.
|
||||||
def startUp(self, context):
|
def startUp(self, context):
|
||||||
self.context = context
|
|
||||||
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
|
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
|
||||||
# raise IngestModuleException("Oh No!")
|
# raise IngestModuleException("Oh No!")
|
||||||
|
self.context = context
|
||||||
|
|
||||||
# Where the analysis is done.
|
# Where the analysis is done.
|
||||||
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
# The 'dataSource' object being passed in is of type org.sleuthkit.datamodel.Content.
|
||||||
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.3/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.4/interfaceorg_1_1sleuthkit_1_1datamodel_1_1_content.html
|
||||||
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
# 'progressBar' is of type org.sleuthkit.autopsy.ingest.DataSourceIngestModuleProgress
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_data_source_ingest_module_progress.html
|
||||||
# TODO: Add your analysis code in here.
|
# TODO: Add your analysis code in here.
|
||||||
def process(self, dataSource, progressBar):
|
def process(self, dataSource, progressBar):
|
||||||
|
|
||||||
# we don't know how much work there is yet
|
# we don't know how much work there is yet
|
||||||
progressBar.switchToIndeterminate()
|
progressBar.switchToIndeterminate()
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
|
||||||
# Use blackboard class to index blackboard artifacts for keyword search
|
# Use blackboard class to index blackboard artifacts for keyword search
|
||||||
# blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
|
||||||
# For our example, we will use FileManager to get all
|
# For our example, we will use FileManager to get all
|
||||||
# files with the word "test"
|
# files with the word "test"
|
||||||
# in the name and then count and read them
|
# in the name and then count and read them
|
||||||
# FileManager API: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1casemodule_1_1services_1_1_file_manager.html
|
# FileManager API: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1casemodule_1_1services_1_1_file_manager.html
|
||||||
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
fileManager = Case.getCurrentCase().getServices().getFileManager()
|
||||||
files = fileManager.findFiles(dataSource, "%test%")
|
files = fileManager.findFiles(dataSource, "%test%")
|
||||||
|
|
||||||
@ -143,12 +142,11 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
|
|||||||
att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file")
|
att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file")
|
||||||
art.addAttribute(att)
|
art.addAttribute(att)
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
try:
|
||||||
#try:
|
# index the artifact for keyword search
|
||||||
# # index the artifact for keyword search
|
blackboard.indexArtifact(art)
|
||||||
# blackboard.indexArtifact(art)
|
except Blackboard.BlackboardException as e:
|
||||||
#except Blackboard.BlackboardException as e:
|
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
||||||
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
|
||||||
|
|
||||||
# To further the example, this code will read the contents of the file and count the number of bytes
|
# To further the example, this code will read the contents of the file and count the number of bytes
|
||||||
inputStream = ReadContentInputStream(file)
|
inputStream = ReadContentInputStream(file)
|
||||||
|
@ -29,7 +29,7 @@
|
|||||||
|
|
||||||
# Simple file-level ingest module for Autopsy.
|
# Simple file-level ingest module for Autopsy.
|
||||||
# Search for TODO for the things that you need to change
|
# Search for TODO for the things that you need to change
|
||||||
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
|
# See http://sleuthkit.org/autopsy/docs/api-docs/4.4/index.html for documentation
|
||||||
|
|
||||||
import jarray
|
import jarray
|
||||||
import inspect
|
import inspect
|
||||||
@ -53,8 +53,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
|
|||||||
from org.sleuthkit.autopsy.casemodule import Case
|
from org.sleuthkit.autopsy.casemodule import Case
|
||||||
from org.sleuthkit.autopsy.casemodule.services import Services
|
from org.sleuthkit.autopsy.casemodule.services import Services
|
||||||
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
from org.sleuthkit.autopsy.casemodule.services import FileManager
|
||||||
# This will work in 4.0.1 and beyond
|
from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
||||||
# from org.sleuthkit.autopsy.casemodule.services import Blackboard
|
|
||||||
|
|
||||||
# Factory that defines the name and details of the module and allows Autopsy
|
# Factory that defines the name and details of the module and allows Autopsy
|
||||||
# to create instances of the modules that will do the anlaysis.
|
# to create instances of the modules that will do the anlaysis.
|
||||||
@ -95,7 +94,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
|
|||||||
|
|
||||||
# Where any setup and configuration is done
|
# Where any setup and configuration is done
|
||||||
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
# 'context' is an instance of org.sleuthkit.autopsy.ingest.IngestJobContext.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1ingest_1_1_ingest_job_context.html
|
||||||
# TODO: Add any setup code that you need here.
|
# TODO: Add any setup code that you need here.
|
||||||
def startUp(self, context):
|
def startUp(self, context):
|
||||||
self.filesFound = 0
|
self.filesFound = 0
|
||||||
@ -106,7 +105,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
|
|||||||
|
|
||||||
# Where the analysis is done. Each file will be passed into here.
|
# Where the analysis is done. Each file will be passed into here.
|
||||||
# The 'file' object being passed in is of type org.sleuthkit.datamodel.AbstractFile.
|
# The 'file' object being passed in is of type org.sleuthkit.datamodel.AbstractFile.
|
||||||
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.3/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html
|
# See: http://www.sleuthkit.org/sleuthkit/docs/jni-docs/4.4/classorg_1_1sleuthkit_1_1datamodel_1_1_abstract_file.html
|
||||||
# TODO: Add your analysis code in here.
|
# TODO: Add your analysis code in here.
|
||||||
def process(self, file):
|
def process(self, file):
|
||||||
# Skip non-files
|
# Skip non-files
|
||||||
@ -115,9 +114,8 @@ class SampleJythonFileIngestModule(FileIngestModule):
|
|||||||
(file.isFile() == False)):
|
(file.isFile() == False)):
|
||||||
return IngestModule.ProcessResult.OK
|
return IngestModule.ProcessResult.OK
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
|
||||||
# Use blackboard class to index blackboard artifacts for keyword search
|
# Use blackboard class to index blackboard artifacts for keyword search
|
||||||
# blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
blackboard = Case.getCurrentCase().getServices().getBlackboard()
|
||||||
|
|
||||||
# For an example, we will flag files with .txt in the name and make a blackboard artifact.
|
# For an example, we will flag files with .txt in the name and make a blackboard artifact.
|
||||||
if file.getName().lower().endswith(".txt"):
|
if file.getName().lower().endswith(".txt"):
|
||||||
@ -132,12 +130,11 @@ class SampleJythonFileIngestModule(FileIngestModule):
|
|||||||
SampleJythonFileIngestModuleFactory.moduleName, "Text Files")
|
SampleJythonFileIngestModuleFactory.moduleName, "Text Files")
|
||||||
art.addAttribute(att)
|
art.addAttribute(att)
|
||||||
|
|
||||||
# This will work in 4.0.1 and beyond
|
try:
|
||||||
#try:
|
# index the artifact for keyword search
|
||||||
# # index the artifact for keyword search
|
blackboard.indexArtifact(art)
|
||||||
# blackboard.indexArtifact(art)
|
except Blackboard.BlackboardException as e:
|
||||||
#except Blackboard.BlackboardException as e:
|
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
||||||
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
|
|
||||||
|
|
||||||
# Fire an event to notify the UI and others that there is a new artifact
|
# Fire an event to notify the UI and others that there is a new artifact
|
||||||
IngestServices.getInstance().fireModuleDataEvent(
|
IngestServices.getInstance().fireModuleDataEvent(
|
||||||
@ -171,4 +168,4 @@ class SampleJythonFileIngestModule(FileIngestModule):
|
|||||||
message = IngestMessage.createMessage(
|
message = IngestMessage.createMessage(
|
||||||
IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName,
|
IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName,
|
||||||
str(self.filesFound) + " files found")
|
str(self.filesFound) + " files found")
|
||||||
ingestServices = IngestServices.getInstance().postMessage(message)
|
ingestServices = IngestServices.getInstance().postMessage(message)
|
@ -35,7 +35,7 @@
|
|||||||
# don't need a configuration UI, start with the other sample module.
|
# don't need a configuration UI, start with the other sample module.
|
||||||
#
|
#
|
||||||
# Search for TODO for the things that you need to change
|
# Search for TODO for the things that you need to change
|
||||||
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
|
# See http://sleuthkit.org/autopsy/docs/api-docs/4.4/index.html for documentation
|
||||||
|
|
||||||
|
|
||||||
import jarray
|
import jarray
|
||||||
@ -204,4 +204,3 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
|
|||||||
# Return the settings used
|
# Return the settings used
|
||||||
def getSettings(self):
|
def getSettings(self):
|
||||||
return self.local_settings
|
return self.local_settings
|
||||||
|
|
||||||
|
@ -31,7 +31,7 @@
|
|||||||
# Sample report module for Autopsy. Use as a starting point for new modules.
|
# Sample report module for Autopsy. Use as a starting point for new modules.
|
||||||
#
|
#
|
||||||
# Search for TODO for the things that you need to change
|
# Search for TODO for the things that you need to change
|
||||||
# See http://sleuthkit.org/autopsy/docs/api-docs/3.1/index.html for documentation
|
# See http://sleuthkit.org/autopsy/docs/api-docs/4.4/index.html for documentation
|
||||||
|
|
||||||
import os
|
import os
|
||||||
from java.lang import System
|
from java.lang import System
|
||||||
@ -69,7 +69,7 @@ class SampleGeneralReportModule(GeneralReportModuleAdapter):
|
|||||||
# TODO: Update this method to make a report
|
# TODO: Update this method to make a report
|
||||||
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath().
|
# The 'baseReportDir' object being passed in is a string with the directory that reports are being stored in. Report should go into baseReportDir + getRelativeFilePath().
|
||||||
# The 'progressBar' object is of type ReportProgressPanel.
|
# The 'progressBar' object is of type ReportProgressPanel.
|
||||||
# See: http://sleuthkit.org/autopsy/docs/api-docs/3.1/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
|
# See: http://sleuthkit.org/autopsy/docs/api-docs/4.4/classorg_1_1sleuthkit_1_1autopsy_1_1report_1_1_report_progress_panel.html
|
||||||
def generateReport(self, baseReportDir, progressBar):
|
def generateReport(self, baseReportDir, progressBar):
|
||||||
|
|
||||||
# For an example, we write a file with the number of files created in the past 2 weeks
|
# For an example, we write a file with the number of files created in the past 2 weeks
|
||||||
|
Loading…
x
Reference in New Issue
Block a user