Merge branch 'release-4.4.0' of https://github.com/sleuthkit/autopsy into develop

This commit is contained in:
U-BASIS\dgrove 2017-04-26 12:18:08 -04:00
commit a23543a72d
73 changed files with 2791 additions and 2252 deletions

View File

@ -34,6 +34,13 @@ import org.sleuthkit.datamodel.TskCoreException;
/**
* 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 {
// This class is a singleton to support multi-selection of nodes, since

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -29,15 +29,24 @@ import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AbstractFile;
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.TskCoreException;
/**
* 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 {
// This class is a singleton to support multi-selection of nodes, since

View File

@ -14,29 +14,12 @@ GetTagNameAndCommentDialog.commentLabel.text=Comment:
GetTagNameAndCommentDialog.cancelButton.text=Cancel
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
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.quickTag=Quick Tag
AddTagAction.noTags=No tags
AddTagAction.newTag=New Tag...
AddTagAction.tagAndComment=Tag and Comment...
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.createTag=Create Tag
GetTagNameAndCommentDialog.cancelName=cancel

View File

@ -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.preexistingLabel.text=\u65E2\u5B58\u30BF\u30B0\uFF1A
GetTagNameDialog.newTagPanel.border.title=\u65B0\u898F\u30BF\u30B0
GetTagNameDialog.tagNameLabel.text=\u30BF\u30B0\u540D\uFF1A
GetTagNameAndCommentDialog.newTagButton.text=\u65B0\u898F\u30BF\u30B0
GetTagNameDialog.preexistingLabel.text=\u65e2\u5b58\u30bf\u30b0\uff1a
GetTagNameDialog.newTagPanel.border.title=\u65b0\u898f\u30bf\u30b0
GetTagNameDialog.tagNameLabel.text=\u30bf\u30b0\u540d\uff1a
GetTagNameAndCommentDialog.newTagButton.text=\u65b0\u898f\u30bf\u30b0
GetTagNameAndCommentDialog.okButton.text=OK
GetTagNameAndCommentDialog.commentText.toolTipText=\u30BF\u30B0\u306E\u30AA\u30D7\u30B7\u30E7\u30CA\u30EB\u306E\u30B3\u30E1\u30F3\u30C8\u3092\u5165\u529B\u307E\u305F\u306F\u7A7A\u6B04\u306B\u3057\u3066\u304F\u3060\u3055\u3044
GetTagNameAndCommentDialog.commentLabel.text=\u30B3\u30E1\u30F3\u30C8\uFF1A
GetTagNameAndCommentDialog.cancelButton.text=\u30AD\u30E3\u30F3\u30BB\u30EB
GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4F7F\u7528\u3059\u308B\u30BF\u30B0\u3092\u9078\u629E
GetTagNameAndCommentDialog.tagLabel.text=\u30BF\u30B0\uFF1A
AddBlackboardArtifactTagAction.singularTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
AddBlackboardArtifactTagAction.pluralTagResult=\u7D50\u679C\u306B\u30BF\u30B0\u3092\u8FFD\u52A0
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
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.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.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC
AddTagAction.quickTag=\u30AF\u30A4\u30C3\u30AF\u30BF\u30B0
AddTagAction.noTags=\u30BF\u30B0\u7121\u3057
AddTagAction.newTag=\u65B0\u898F\u30BF\u30B0\u2026
AddTagAction.tagAndComment=\u30BF\u30B0\u3068\u30B3\u30E1\u30F3\u30C8\u3092\u8FFD\u52A0\u2026
DeleteBlackboardArtifactTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664
DeleteBlackboardArtifactTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002
DeleteBlackboardArtifactTagAction.tagDelErr=\u30BF\u30B0\u524A\u9664\u30A8\u30E9\u30FC
DeleteContentTagAction.deleteTags=\u30BF\u30B0\u3092\u524A\u9664
DeleteContentTagAction.unableToDelTag.msg=\u30BF\u30B0{0}\u3092\u524A\u9664\u3067\u304D\u307E\u305B\u3093\u3002
DeleteContentTagAction.tagDelErr=\u30BF\u30B0\u306E\u524A\u9664\u30A8\u30E9\u30FC
GetTagNameAndCommentDialog.noTags=\u30BF\u30B0\u7121\u3057
GetTagNameAndCommentDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210
GetTagNameAndCommentDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB
GetTagNameDialog.createTag=\u30BF\u30B0\u3092\u4F5C\u6210
GetTagNameDialog.cancelName=\u30AD\u30E3\u30F3\u30BB\u30EB
GetTagNameDialog.mustSupplyTtagName.msg=\u30BF\u30B0\u540D\u3092\u6307\u5B9A\u3057\u306A\u3051\u308C\u3070\u5148\u306B\u9032\u3081\u307E\u305B\u3093\u3002
GetTagNameDialog.tagNameErr=\u30BF\u30B0\u540D
GetTagNameDialog.illegalCharsErr=\u4F7F\u7528\u3067\u304D\u306A\u3044\u6587\u5B57
GetTagNameDialog.unableToAddTagNameToCase.msg=\u30BF\u30B0\u540D{0}\u3092\u30B1\u30FC\u30B9\u306B\u8FFD\u52A0\u3067\u304D\u307E\u305B\u3093\u3067\u3057\u305F\u3002
GetTagNameDialog.taggingErr=\u30BF\u30B0\u4ED8\u3051\u30A8\u30E9\u30FC
GetTagNameDialog.tagNameAlreadyDef.msg=\u30BF\u30B0\u540D{0}\u306F\u65E2\u306B\u5B9A\u7FA9\u3055\u308C\u3066\u3044\u307E\u3059\u3002
GetTagNameDialog.dupTagErr=\u30BF\u30B0\u306E\u91CD\u8907\u30A8\u30E9\u30FC
AddContentTagAction.cannotApplyTagErr=\u30BF\u30B0\u3092\u9069\u7528\u3067\u304D\u307E\u305B\u3093
OpenLogFolder.error1=\u30ED\u30B0\u30D5\u30A1\u30A4\u30EB\u304C\u898B\u3064\u304B\u308A\u307E\u305B\u3093\u3067\u3057\u305F\uFF1A{0}
CTL_OpenLogFolder=\u30ED\u30B0\u30D5\u30A9\u30EB\u30C0\u3092\u958B\u304F
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_OpenPythonModulesFolderAction=Python\u30D7\u30E9\u30B0\u30A4\u30F3
OpenPythonModulesFolderAction.actionName.text=Python\u30D7\u30E9\u30B0\u30A4\u30F3
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}
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
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
GetTagNameAndCommentDialog.commentText.toolTipText=\u30bf\u30b0\u306e\u30aa\u30d7\u30b7\u30e7\u30ca\u30eb\u306e\u30b3\u30e1\u30f3\u30c8\u3092\u5165\u529b\u307e\u305f\u306f\u7a7a\u6b04\u306b\u3057\u3066\u304f\u3060\u3055\u3044
GetTagNameAndCommentDialog.commentLabel.text=\u30b3\u30e1\u30f3\u30c8\uff1a
GetTagNameAndCommentDialog.cancelButton.text=\u30ad\u30e3\u30f3\u30bb\u30eb
GetTagNameAndCommentDialog.tagCombo.toolTipText=\u4f7f\u7528\u3059\u308b\u30bf\u30b0\u3092\u9078\u629e
GetTagNameAndCommentDialog.tagLabel.text=\u30bf\u30b0\uff1a
AddBlackboardArtifactTagAction.singularTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
AddBlackboardArtifactTagAction.pluralTagResult=\u7d50\u679c\u306b\u30bf\u30b0\u3092\u8ffd\u52a0
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
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.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.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc
AddTagAction.quickTag=\u30af\u30a4\u30c3\u30af\u30bf\u30b0
AddTagAction.noTags=\u30bf\u30b0\u7121\u3057
AddTagAction.newTag=\u65b0\u898f\u30bf\u30b0\u2026
AddTagAction.tagAndComment=\u30bf\u30b0\u3068\u30b3\u30e1\u30f3\u30c8\u3092\u8ffd\u52a0\u2026
GetTagNameAndCommentDialog.noTags=\u30bf\u30b0\u7121\u3057
GetTagNameAndCommentDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210
GetTagNameAndCommentDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb
GetTagNameDialog.createTag=\u30bf\u30b0\u3092\u4f5c\u6210
GetTagNameDialog.cancelName=\u30ad\u30e3\u30f3\u30bb\u30eb
GetTagNameDialog.mustSupplyTtagName.msg=\u30bf\u30b0\u540d\u3092\u6307\u5b9a\u3057\u306a\u3051\u308c\u3070\u5148\u306b\u9032\u3081\u307e\u305b\u3093\u3002
GetTagNameDialog.tagNameErr=\u30bf\u30b0\u540d
GetTagNameDialog.illegalCharsErr=\u4f7f\u7528\u3067\u304d\u306a\u3044\u6587\u5b57
GetTagNameDialog.unableToAddTagNameToCase.msg=\u30bf\u30b0\u540d{0}\u3092\u30b1\u30fc\u30b9\u306b\u8ffd\u52a0\u3067\u304d\u307e\u305b\u3093\u3067\u3057\u305f\u3002
GetTagNameDialog.taggingErr=\u30bf\u30b0\u4ed8\u3051\u30a8\u30e9\u30fc
GetTagNameDialog.tagNameAlreadyDef.msg=\u30bf\u30b0\u540d{0}\u306f\u65e2\u306b\u5b9a\u7fa9\u3055\u308c\u3066\u3044\u307e\u3059\u3002
GetTagNameDialog.dupTagErr=\u30bf\u30b0\u306e\u91cd\u8907\u30a8\u30e9\u30fc
AddContentTagAction.cannotApplyTagErr=\u30bf\u30b0\u3092\u9069\u7528\u3067\u304d\u307e\u305b\u3093
OpenLogFolder.error1=\u30ed\u30b0\u30d5\u30a1\u30a4\u30eb\u304c\u898b\u3064\u304b\u308a\u307e\u305b\u3093\u3067\u3057\u305f\uff1a{0}
CTL_OpenLogFolder=\u30ed\u30b0\u30d5\u30a9\u30eb\u30c0\u3092\u958b\u304f
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_OpenPythonModulesFolderAction=Python\u30d7\u30e9\u30b0\u30a4\u30f3
OpenPythonModulesFolderAction.actionName.text=Python\u30d7\u30e9\u30b0\u30a4\u30f3
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}
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
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

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2016 Basis Technology Corp.
* Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,26 +20,42 @@ package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.util.Collection;
import java.util.HashSet;
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.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
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.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({
"DeleteBlackboardArtifactTagAction.deleteTag=Delete Tag",
"# {0} - tagName",
"DeleteBlackboardArtifactTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
"DeleteBlackboardArtifactTagAction.tagDelErr=Tag Deletion Error"
})
public class DeleteBlackboardArtifactTagAction extends AbstractAction {
private static final Logger LOGGER = Logger.getLogger(DeleteBlackboardArtifactTagAction.class.getName());
private static final long serialVersionUID = 1L;
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
// 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 {
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
} 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(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),
@ -81,28 +97,4 @@ public class DeleteBlackboardArtifactTagAction extends AbstractAction {
}).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() {
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2015 Basis Technology Corp.
* Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,25 +20,41 @@ package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent;
import java.util.Collection;
import java.util.HashSet;
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.JOptionPane;
import javax.swing.SwingUtilities;
import javax.swing.SwingWorker;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
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({
"DeleteContentTagAction.deleteTag=Delete Tag",
"# {0} - tagName",
"DeleteContentTagAction.unableToDelTag.msg=Unable to delete tag {0}.",
"DeleteContentTagAction.tagDelErr=Tag Deletion Error"
})
public class DeleteContentTagAction extends AbstractAction {
private static final Logger LOGGER = Logger.getLogger(DeleteContentTagAction.class.getName());
private static final long serialVersionUID = 1L;
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
// 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 {
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
} 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(() -> {
JOptionPane.showMessageDialog(null,
NbBundle.getMessage(this.getClass(),

View File

@ -0,0 +1,201 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.sleuthkit.autopsy.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);
}
}
}
}
}

View 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);
}
}
}
}
}

View File

@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.casemodule;
import java.util.ArrayList;
import java.util.List;
import java.util.logging.Level;
import javax.annotation.concurrent.GuardedBy;
import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback.DataSourceProcessorResult;
@ -61,6 +62,8 @@ class AddImageTask implements Runnable {
* TODO (AUT-2021): Merge SleuthkitJNI.AddImageProcess and AddImageTask
*/
private final Object tskAddImageProcessLock;
@GuardedBy("tskAddImageProcessLock")
private boolean tskAddImageProcessStopped;
private SleuthkitJNI.CaseDbHandle.AddImageProcess tskAddImageProcess;
@ -77,8 +80,9 @@ class AddImageTask implements Runnable {
* java.util.TimeZone.getID.
* @param ignoreFatOrphanFiles Whether to parse orphans if the image has a
* FAT filesystem.
* @param imageWriterPath Path that a copy of the image should be written to.
* Use empty string to disable image writing
* @param imageWriterPath Path that a copy of the image should be
* written to. Use empty string to disable image
* writing
* @param progressMonitor Progress monitor to report progress during
* processing.
* @param callback Callback to call when processing is done.
@ -104,7 +108,7 @@ class AddImageTask implements Runnable {
progressMonitor.setProgress(0);
Case currentCase = Case.getCurrentCase();
String imageWriterPath = "";
if(imageWriterSettings != null){
if (imageWriterSettings != null) {
imageWriterPath = imageWriterSettings.getPath();
}
List<String> errorMessages = new ArrayList<>();
@ -112,8 +116,12 @@ class AddImageTask implements Runnable {
try {
currentCase.getSleuthkitCase().acquireExclusiveLock();
synchronized (tskAddImageProcessLock) {
tskAddImageProcess = currentCase.getSleuthkitCase().makeAddImageProcess(timeZone, true,
ignoreFatOrphanFiles, imageWriterPath);
if (!tskAddImageProcessStopped) { //if we have already cancelled don't bother making an addImageProcess
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));
progressUpdateThread.start();
@ -142,6 +150,7 @@ class AddImageTask implements Runnable {
*/
public void cancelTask() {
synchronized (tskAddImageProcessLock) {
tskAddImageProcessStopped = true;
if (null != tskAddImageProcess) {
try {
/*
@ -153,7 +162,7 @@ class AddImageTask implements Runnable {
* called.
*/
tskAddImageProcess.stop();
tskAddImageProcessStopped = true;
} catch (TskCoreException ex) {
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()) {
errorMessages.add(verificationError);
}
if(imageWriterSettings != null){
ImageWriterService.createImageWriter(imageId, imageWriterSettings);
if (imageWriterSettings != null) {
ImageWriterService.createImageWriter(imageId, imageWriterSettings);
}
newDataSources.add(newImage);
} else {
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);
criticalErrorOccurred = true;
}

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.casemodule;
import java.awt.Color;
import java.awt.Cursor;
import java.awt.EventQueue;
import java.awt.Window;
import java.util.ArrayList;
@ -36,6 +37,7 @@ import org.openide.WizardDescriptor;
import org.openide.util.HelpCtx;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessor;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorCallback;
import org.sleuthkit.autopsy.corecomponentinterfaces.DataSourceProcessorProgressMonitor;
@ -319,8 +321,10 @@ class AddImageWizardAddingProgressPanel extends ShortcutWizardDescriptorPanel {
cleanupTask = addImageAction.new CleanupTask() {
@Override
void cleanup() throws Exception {
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.WAIT_CURSOR));
cancelDataSourceProcessing(dataSourceId);
cancelled = true;
WindowManager.getDefault().getMainWindow().setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
};

View File

@ -148,6 +148,7 @@ GeneralFilter.encaseImageDesc.text=Encase Images (*.e01)
GeneralFilter.virtualMachineImageDesc.text=Virtual Machines (*.vmdk, *.vhd)
GeneralFilter.executableDesc.text=Executables (*.exe)
ImageDSProcessor.dsType.text=Disk Image or VM File
GeneralFilter.graphicImageDesc.text=Images (*.png, *.jpg, *.jpeg, *.gif, *.bmp)
ImageDSProcessor.allDesc.text=All Supported Types
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.

View File

@ -113,10 +113,8 @@ import org.sleuthkit.datamodel.TskCoreException;
*/
public class Case {
private static final int NAME_LOCK_TIMOUT_HOURS = 12;
private static final int SHARED_DIR_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 int DIR_LOCK_TIMOUT_HOURS = 12;
private static final int RESOURCES_LOCK_TIMOUT_HOURS = 12;
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 CACHE_FOLDER = "Cache"; //NON-NLS
@ -475,18 +473,21 @@ public class Case {
}
if (null != currentCase) {
String previousCaseDisplayName = currentCase.getDisplayName();
String previousCaseName = currentCase.getName();
String previousCaseDir = currentCase.getCaseDirectory();
try {
closeCurrentCase();
} 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();
newCurrentCase.open(caseDir, caseDisplayName, caseNumber, examiner, caseType);
newCurrentCase.create(caseType, caseDir, caseDisplayName, caseNumber, examiner);
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()) {
updateGUIForCaseOpened(newCurrentCase);
}
@ -723,83 +724,42 @@ public class Case {
}
/**
* Transforms the display name for a case to make a suitable case name for
* use in case directory paths, coordination service locks, Active MQ
* message channels, etc.
*
* ActiveMQ:
* http://activemq.2283324.n4.nabble.com/What-are-limitations-restrictions-on-destination-name-td4664141.html
* may not be ?
* Transforms a case display name into a unique case name that can be used
* to identify the case even if the display name is changed.
*
* @param caseDisplayName A case display name.
*
* @return The case display name transformed into a corresponding case name.
*
* @throws org.sleuthkit.autopsy.casemodule.Case.IllegalCaseNameException
* @return The unique case name.
*/
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
/*
* Remove /, \, :, ?, space, ' ".
*/
caseName = caseName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
uniqueCaseName = uniqueCaseName.replaceAll("[ /?:'\"\\\\]", "_"); //NON-NLS
/*
* Make it all lowercase.
*/
caseName = caseName.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;
}
uniqueCaseName = uniqueCaseName.toLowerCase();
/*
* Truncate to 63-16=47 chars to accomodate the timestamp, then add the
* timestamp.
* Add a time stamp for uniqueness.
*/
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");
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 {
try {
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) {
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
* will be created if it doesn't already exist; if it
* 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 examiner The examiner to associate with the case, can be
* 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
* exception will have a user-friendly message
@ -1602,24 +1562,12 @@ public class Case {
* exception.
*/
@Messages({
"Case.exceptionMessage.illegalCaseName=Case name contains illegal characters.",
"Case.progressIndicatorTitle.creatingCase=Creating Case",
"Case.progressIndicatorCancelButton.label=Cancel",
"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>"
})
private void open(String caseDir, String caseDisplayName, String caseNumber, String examiner, CaseType caseType) 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);
}
private void create(CaseType caseType, String caseDir, String caseDisplayName, String caseNumber, String examiner) throws CaseActionException {
/*
* Set up either a GUI progress indicator or a logging progress
* indicator.
@ -1648,7 +1596,7 @@ public class Case {
caseLockingExecutor = Executors.newSingleThreadExecutor();
Future<Void> future = caseLockingExecutor.submit(() -> {
if (CaseType.SINGLE_USER_CASE == caseType) {
open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator);
create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
} else {
/*
* Acquire a shared case directory lock that will be held as
@ -1657,6 +1605,7 @@ public class Case {
*/
progressIndicator.start(Bundle.Case_progressMessage_openingCaseResources());
acquireSharedCaseDirLock(caseDir);
/*
* Acquire an exclusive case resources lock to ensure only one
* node at a time can create/open/upgrade/close the case
@ -1665,14 +1614,14 @@ public class Case {
try (CoordinationService.Lock resourcesLock = acquireExclusiveCaseResourcesLock(caseDir)) {
assert (null != resourcesLock);
try {
open(caseDir, caseName, caseDisplayName, caseNumber, examiner, caseType, progressIndicator);
create(caseType, caseDir, caseDisplayName, caseNumber, examiner, progressIndicator);
} catch (CaseActionException ex) {
/*
* Release the case directory lock immediately if there
* was a problem opening the case.
*/
if (CaseType.MULTI_USER_CASE == caseType) {
releaseSharedCaseDirLock(caseName);
releaseSharedCaseDirLock(caseDir);
}
throw ex;
}
@ -1696,7 +1645,6 @@ public class Case {
*/
try {
future.get();
} catch (InterruptedException ex) {
throw new CaseActionException(Bundle.Case_exceptionMessage_wrapperMessage(ex.getMessage()), 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
* will be created if it doesn't already exist; if it
* exists, it is ASSUMED it was created by calling
* createCaseDirectory.
* @param caseDisplayName The display name of case, which may be changed
* later by the user.
* @param caseNumber The case number, can be the empty string.
* @param examiner The examiner to associate with the case, can be
* the empty string.
* @param caseType The type of case (single-user or multi-user).
* @param caseType The type of case (single-user or multi-user).
* @param caseDir The full path of the case directory. The
* directory will be created if it doesn't already
* exist; if it exists, it is ASSUMED it was
* created by calling createCaseDirectory.
* @param caseName The case name.
* @param caseDisplayName The display name of case, which may be changed
* later by the user.
* @param caseNumber The case number, can be the empty string.
* @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
* exception will have a user-friendly message
@ -1730,6 +1680,7 @@ public class Case {
* exception.
*/
@Messages({
"Case.exceptionMessage.emptyCaseName=Case name is empty.",
"Case.progressMessage.creatingCaseDirectory=Creating case directory...",
"Case.progressMessage.creatingCaseDatabase=Creating case database...",
"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.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.
*
@ -1768,32 +1727,26 @@ public class Case {
*/
progressIndicator.progress(Bundle.Case_progressMessage_creatingCaseDatabase());
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 {
if (CaseType.SINGLE_USER_CASE == caseType) {
/*
* 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());
} else if (CaseType.MULTI_USER_CASE == caseType) {
/*
* 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) {
throw new CaseActionException(Bundle.Case_exceptionMessage_couldNotCreateCaseDatabase(), ex);
} catch (UserPreferencesException ex) {
throw new CaseActionException(NbBundle.getMessage(Case.class, "Case.databaseConnectionInfo.error.msg"), ex);
}
@ -1814,7 +1767,7 @@ public class 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
* exception will have a user-friendly message
@ -1980,7 +1933,8 @@ public class Case {
"Case.progressMessage.settingUpNetworkCommunications=Setting up network communications...",})
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());
Logger.setLogDirectory(getLogDirectoryPath());
@ -1989,12 +1943,11 @@ public class Case {
* Hook up a SleuthKit layer error reporter.
*/
progressIndicator.progress(Bundle.Case_progressMessage_settingUpTskErrorReporting());
this.sleuthkitErrorReporter = new SleuthkitErrorReporter(MIN_SECS_BETWEEN_TSK_ERROR_REPORTS, NbBundle.getMessage(Case.class, "IntervalErrorReport.ErrorText"));
this.caseDb.addErrorObserver(this.sleuthkitErrorReporter);
/*
* Clear the temp subdirectory.
* Clear the temp subdirectory of the case directory.
*/
progressIndicator.progress(Bundle.Case_progressMessage_clearingTempDirectory());
Case.clearTempSubDir(this.getTempDirectory());
@ -2335,7 +2288,7 @@ public class Case {
@Messages({"Case.creationException.couldNotAcquireDirLock=Failed to get lock on case directory."})
private void acquireSharedCaseDirLock(String caseDir) throws CaseActionException {
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) {
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.
*

View File

@ -125,7 +125,7 @@ public final class CaseMetadata {
* created.
*/
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.caseName = caseName;
this.caseDisplayName = caseDisplayName;

View File

@ -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 String ENCASE_IMAGE_DESC = NbBundle.getMessage(GeneralFilter.class,
"GeneralFilter.encaseImageDesc.text");
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,
"GeneralFilter.virtualMachineImageDesc.text");
"GeneralFilter.virtualMachineImageDesc.text");
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 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 String desc;

View File

@ -204,25 +204,19 @@ class NewCaseWizardPanel1 implements WizardDescriptor.ValidatingPanel<WizardDesc
@Override
public void validate() throws WizardValidationException {
String caseDisplayName = getComponent().getCaseName();
String caseParentDir = getComponent().getCaseParentDir();
// check if case Name contain one of this following symbol:
// \ / : * ? " < > |
if (!Case.isValidName(caseDisplayName)) {
/*
* 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
* names, since it will be used as the name of the case directory.
*/
String caseName = getComponent().getCaseName();
if (!Case.isValidName(caseName)) {
String errorMsg = NbBundle
.getMessage(this.getClass(), "NewCaseWizardPanel1.validate.errMsg.invalidSymbols");
validationError(errorMsg);
} 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;
// check if the directory exist

View File

@ -43,7 +43,7 @@ import org.sleuthkit.datamodel.TskData;
/**
* Import a case from single-user to multi-user.
*
*
* DO NOT USE, NEEDS TO BE UPDATED
*/
public class SingleUserCaseConverter {
@ -175,9 +175,15 @@ public class SingleUserCaseConverter {
}
// 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
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);
// Copy items to new hostname folder structure
@ -493,12 +499,12 @@ public class SingleUserCaseConverter {
if (value > biggestPK) {
biggestPK = value;
}
// 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.
int encoding = TskData.EncodingType.NONE.getType();
ResultSetMetaData rsMetaData = inputResultSet.getMetaData();
if(rsMetaData.getColumnCount() == 3){
if (rsMetaData.getColumnCount() == 3) {
encoding = inputResultSet.getInt(3);
}
outputStatement.executeUpdate("INSERT INTO tsk_files_path (obj_id, path, encoding_type) VALUES (" //NON-NLS

View File

@ -55,15 +55,16 @@ public final class UserPreferences {
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_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_PORT = "IndexingServerPort"; //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_HOST = "MessageServiceHost"; //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_HOURS = "ProcessTimeOutHours"; //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 AGENCY_LOGO_IMAGE_PATH = "AgencyLogoImagePath"; //NON-NLS
private static final int DEFAULT_PROCESS_TIMEOUT_HR = 60;
private static final String DEFAULT_PORT_STRING = "61616";
private static final int DEFAULT_PORT_INT = 61616;
@ -302,7 +303,7 @@ public final class UserPreferences {
public static void setIsTimeOutEnabled(boolean enabled) {
preferences.putBoolean(PROCESS_TIME_OUT_ENABLED, enabled);
}
/**
* Get the display name for this program
* @return Name of this program
@ -310,17 +311,17 @@ public final class UserPreferences {
public static String getAppName(){
return preferences.get(APP_NAME, "Autopsy");
}
/**
* Set the display name for this program
*
*
* @param name Display name
*/
public static void setAppName(String name){
preferences.put(APP_NAME, name);
}
/**
* Provides ability to convert text to hex text.
*/

View File

@ -46,37 +46,19 @@
<Layout>
<DimensionLayout dim="0">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<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="103" groupAlignment="0" 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"/>
<Group type="103" groupAlignment="0" attributes="0">
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
<Component id="useGMTTimeRB" alignment="0" min="-2" max="-2" attributes="0"/>
</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="useBestViewerRB" min="-2" max="-2" attributes="0"/>
<Component id="dataSourcesHideKnownCB" alignment="0" min="-2" max="-2" attributes="0"/>
@ -84,7 +66,26 @@
</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>
@ -92,7 +93,7 @@
</DimensionLayout>
<DimensionLayout dim="1">
<Group type="103" groupAlignment="0" attributes="0">
<Group type="102" attributes="0">
<Group type="102" alignment="0" attributes="0">
<EmptySpace max="-2" attributes="0"/>
<Component id="jLabelSelectFile" min="-2" max="-2" attributes="0"/>
<EmptySpace max="-2" attributes="0"/>
@ -117,7 +118,14 @@
<Component id="useLocalTimeRB" min="-2" max="-2" attributes="0"/>
<EmptySpace 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>
</DimensionLayout>
@ -249,6 +257,36 @@
</Property>
</Properties>
</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, &quot;{key}&quot;)"/>
</Property>
</Properties>
</Component>
<Component class="javax.swing.JTextField" name="agencyLogoPathField">
<Properties>
<Property name="editable" type="boolean" value="false"/>
<Property name="background" type="java.awt.Color" editor="org.netbeans.beaninfo.editors.ColorEditor">
<Color blue="ff" green="ff" red="ff" type="rgb"/>
</Property>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.agencyLogoPathField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
<Property name="focusable" type="boolean" value="false"/>
<Property name="requestFocusEnabled" type="boolean" value="false"/>
</Properties>
</Component>
<Component class="javax.swing.JButton" name="browseLogosButton">
<Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/corecomponents/Bundle.properties" key="AutopsyOptionsPanel.browseLogosButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="browseLogosButtonActionPerformed"/>
</Events>
</Component>
</SubComponents>
</Container>
</SubComponents>

View File

@ -18,8 +18,13 @@
*/
package org.sleuthkit.autopsy.corecomponents;
import java.io.File;
import javax.swing.JFileChooser;
import org.netbeans.spi.options.OptionsPanelController;
import org.sleuthkit.autopsy.casemodule.GeneralFilter;
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.
@ -27,9 +32,14 @@ import org.sleuthkit.autopsy.core.UserPreferences;
final class AutopsyOptionsPanel extends javax.swing.JPanel {
private static final long serialVersionUID = 1L;
private final JFileChooser fc;
AutopsyOptionsPanel() {
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() {
@ -43,6 +53,7 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
boolean useLocalTime = UserPreferences.displayTimesInLocalTime();
useLocalTimeRB.setSelected(useLocalTime);
useGMTTimeRB.setSelected(!useLocalTime);
agencyLogoPathField.setText(ModuleSettings.getConfigSetting(ReportBranding.MODULE_NAME, ReportBranding.AGENCY_LOGO_PATH_PROP));
}
void store() {
@ -52,6 +63,12 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
UserPreferences.setHideSlackFilesInDataSourcesTree(dataSourcesHideSlackCB.isSelected());
UserPreferences.setHideSlackFilesInViewsTree(viewsHideSlackCB.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() {
@ -82,6 +99,9 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
dataSourcesHideSlackCB = new javax.swing.JCheckBox();
viewsHideSlackCB = new javax.swing.JCheckBox();
jLabelHideSlackFiles = new javax.swing.JLabel();
agencyLogoImageLabel = new javax.swing.JLabel();
agencyLogoPathField = new javax.swing.JTextField();
browseLogosButton = new javax.swing.JButton();
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(agencyLogoImageLabel, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoImageLabel.text")); // NOI18N
agencyLogoPathField.setEditable(false);
agencyLogoPathField.setBackground(new java.awt.Color(255, 255, 255));
agencyLogoPathField.setText(org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.agencyLogoPathField.text")); // NOI18N
agencyLogoPathField.setFocusable(false);
agencyLogoPathField.setRequestFocusEnabled(false);
org.openide.awt.Mnemonics.setLocalizedText(browseLogosButton, org.openide.util.NbBundle.getMessage(AutopsyOptionsPanel.class, "AutopsyOptionsPanel.browseLogosButton.text")); // NOI18N
browseLogosButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
browseLogosButtonActionPerformed(evt);
}
});
javax.swing.GroupLayout jPanel1Layout = new javax.swing.GroupLayout(jPanel1);
jPanel1.setLayout(jPanel1Layout);
jPanel1Layout.setHorizontalGroup(
@ -162,33 +197,32 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addGroup(jPanel1Layout.createSequentialGroup()
.addContainerGap()
.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.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelTimeDisplay)
.addComponent(jLabelHideKnownFiles)
.addComponent(jLabelSelectFile)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(useLocalTimeRB)
.addComponent(useGMTTimeRB)
.addComponent(keepCurrentViewerRB)
.addComponent(useBestViewerRB)
.addComponent(dataSourcesHideKnownCB)
.addComponent(viewsHideKnownCB))))
.addContainerGap(javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
.addContainerGap(140, Short.MAX_VALUE))
.addGroup(jPanel1Layout.createSequentialGroup()
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addComponent(jLabelHideSlackFiles)
.addComponent(agencyLogoImageLabel)
.addGroup(jPanel1Layout.createSequentialGroup()
.addGap(10, 10, 10)
.addGroup(jPanel1Layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
.addGroup(jPanel1Layout.createSequentialGroup()
.addComponent(agencyLogoPathField, javax.swing.GroupLayout.PREFERRED_SIZE, 259, javax.swing.GroupLayout.PREFERRED_SIZE)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.addComponent(browseLogosButton))
.addComponent(dataSourcesHideSlackCB)
.addComponent(viewsHideSlackCB))))
.addGap(0, 0, Short.MAX_VALUE))))
@ -220,7 +254,13 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
.addComponent(useLocalTimeRB)
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
.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);
@ -269,7 +309,19 @@ final class AutopsyOptionsPanel extends javax.swing.JPanel {
firePropertyChange(OptionsPanelController.PROP_CHANGED, null, null);
}//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
private javax.swing.JLabel agencyLogoImageLabel;
private javax.swing.JTextField agencyLogoPathField;
private javax.swing.JButton browseLogosButton;
private javax.swing.ButtonGroup buttonGroup1;
private javax.swing.ButtonGroup buttonGroup3;
private javax.swing.JCheckBox dataSourcesHideKnownCB;

View File

@ -194,3 +194,7 @@ MultiUserSettingsPanel.InvalidPortNumber=Invalid port number
AutopsyOptionsPanel.jLabelHideSlackFiles.text=Hide slack files in the:
AutopsyOptionsPanel.dataSourcesHideSlackCB.text=Data Sources area (the directory hierarchy)
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=

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013 Basis Technology Corp.
* Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,18 +19,25 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
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.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
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.DerivedFile;
import org.sleuthkit.datamodel.Directory;
@ -64,129 +71,227 @@ public class DataModelActionsFactory {
.getMessage(DataModelActionsFactory.class, "DataModelActionsFactory.srfFileSameMD5.text");
public static List<Action> getActions(File file, boolean isArtifactSource) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
final FileNode fileNode = new FileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, fileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, fileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction(SEARCH_FOR_FILES_SAME_MD5, fileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), slackFile));
final SlackFileNode slackFileNode = new SlackFileNode(slackFile);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, slackFileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
LayoutFileNode layoutFileNode = new LayoutFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());//
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, layoutFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, layoutFileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());//
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
DirectoryNode directoryNode = new DirectoryNode(directory);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), directory));
VirtualDirectoryNode directoryNode = new VirtualDirectoryNode(directory);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, directoryNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, directoryNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
final LocalFileNode localFileNode = new LocalFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {
List<Action> actions = new ArrayList<>();
actions.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
List<Action> actionsList = new ArrayList<>();
actionsList.add(new ViewContextAction((isArtifactSource ? VIEW_SOURCE_FILE_IN_DIR : VIEW_FILE_IN_DIR), file));
final LocalFileNode localFileNode = new LocalFileNode(file);
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actions.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(VIEW_IN_NEW_WINDOW, localFileNode));
actionsList.add(new ExternalViewerAction(OPEN_IN_EXTERNAL_VIEWER, localFileNode));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
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) {

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011 - 2013 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,11 +19,16 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
@ -37,6 +42,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
* are more directories.
*/
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 DOTDIR = NbBundle.getMessage(DirectoryNode.class, "DirectoryNode.curFolder.text");
@ -71,23 +78,29 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
*/
@Override
public Action[] getActions(boolean popup) {
List<Action> actions = new ArrayList<>();
List<Action> actionsList = new ArrayList<>();
for (Action a : super.getActions(true)) {
actions.add(a);
actionsList.add(a);
}
if (!getDirectoryBrowseMode()) {
actions.add(new ViewContextAction(
actionsList.add(new ViewContextAction(
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));
actions.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[actions.size()]);
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "DirectoryNode.viewInNewWin.text"), this));
actionsList.add(ViewFileInTimelineAction.createViewFileAction(getContent()));
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
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());
return actionsList.toArray(new Action[actionsList.size()]);
}
@Override

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,13 +19,18 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.Action;
import org.apache.commons.lang3.StringUtils;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.ImageUtils;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
@ -41,6 +46,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_NAME_FLAG_ENUM;
* children.
*/
public class FileNode extends AbstractFsContentNode<AbstractFile> {
private static final Logger LOGGER = Logger.getLogger(FileNode.class.getName());
/**
* Constructor
@ -96,6 +103,12 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
actionsList.add(new HashSearchAction(Bundle.FileNode_getActions_searchFilesSameMD5_text(), this));
actionsList.add(null); // creates a menu separator
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());
return actionsList.toArray(new Action[actionsList.size()]);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,17 +19,22 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskData;
@ -121,6 +126,13 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
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());
return actionsList.toArray(new Action[0]);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-2016 Basis Technology Corp.
* Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -20,14 +20,19 @@ package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import javax.swing.Action;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
@ -39,6 +44,8 @@ import org.sleuthkit.datamodel.AbstractFile;
* A Node for a LocalFile or DerivedFile content object.
*/
public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
private static final Logger LOGGER = Logger.getLogger(LocalFileNode.class.getName());
public LocalFileNode(AbstractFile af) {
super(af);
@ -98,6 +105,13 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
NbBundle.getMessage(this.getClass(), "LocalFileNode.getActions.searchFilesSameMd5.text"), this));
actionsList.add(null); // creates a menu separator
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());
return actionsList.toArray(new Action[0]);
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2016 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,10 +19,14 @@
package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
@ -84,6 +88,13 @@ public class SlackFileNode extends AbstractFsContentNode<AbstractFile> {
actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
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());
return actionsList.toArray(new Action[actionsList.size()]);
}

View File

@ -21,6 +21,8 @@ package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent;
import java.beans.PropertyVetoException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import java.util.logging.Level;
import java.util.prefs.PreferenceChangeEvent;
@ -33,8 +35,11 @@ import org.openide.nodes.FilterNode;
import org.openide.nodes.Node;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
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.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger;
@ -70,6 +75,8 @@ import org.sleuthkit.datamodel.VirtualDirectory;
* defines the actions that the node should have.
*/
public class DataResultFilterNode extends FilterNode {
private static final Logger LOGGER = Logger.getLogger(DataResultFilterNode.class.getName());
private static boolean filterKnownFromDataSources = UserPreferences.hideKnownFilesInDataSourcesTree();
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
// 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
for (Action a : ban.getActions(true)) {
actions.add(a);
actionsList.add(a);
}
BlackboardArtifact ba = ban.getLookup().lookup(BlackboardArtifact.class);
final int artifactTypeID = ba.getArtifactTypeID();
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_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));
} else {
// if the artifact links to another file, add an action to go to
// that file
Content c = findLinked(ban);
if (c != null) {
actions.add(new ViewContextAction(
actionsList.add(new ViewContextAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.viewFileInDir.text"), c));
}
// 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));
}
Content c = ban.getLookup().lookup(File.class);
@ -304,28 +311,44 @@ public class DataResultFilterNode extends FilterNode {
n = new SlackFileNode((SlackFile) c);
}
if (n != null) {
actions.add(null); // creates a menu separator
actions.add(new NewWindowViewAction(
actionsList.add(null); // creates a menu separator
actionsList.add(new NewWindowViewAction(
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));
actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance());
if (md5Action) {
actions.add(new HashSearchAction(
actionsList.add(new HashSearchAction(
NbBundle.getMessage(this.getClass(), "DataResultFilterNode.action.searchFilesSameMd5.text"), n));
}
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
actionsList.add(null); // creates a menu separator
actionsList.add(AddContentTagAction.getInstance());
actionsList.add(AddBlackboardArtifactTagAction.getInstance());
final Collection<AbstractFile> selectedFilesList =
new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
if(selectedFilesList.size() == 1) {
actionsList.add(DeleteFileContentTagAction.getInstance());
}
} else {
// There's no specific file associated with the artifact, but
// we can still tag the artifact itself
actions.add(null);
actions.add(AddBlackboardArtifactTagAction.getInstance());
actionsList.add(null);
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

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2014 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -19,13 +19,18 @@
package org.sleuthkit.autopsy.directorytree;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import javax.swing.AbstractAction;
import javax.swing.Action;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.DerivedFile;
@ -85,48 +90,82 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
@Override
public List<? extends Action> visit(final Directory d) {
List<Action> actions = new ArrayList<>();
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
List<Action> actionsList = new ArrayList<>();
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());
return actionsList;
}
@Override
public List<? extends Action> visit(final VirtualDirectory d) {
List<Action> actions = new ArrayList<>();
List<Action> actionsList = new ArrayList<>();
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());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
actionsList.add(ExtractAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList;
}
@Override
public List<? extends Action> visit(final DerivedFile d) {
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
List<Action> actionsList = new ArrayList<>();
actionsList.add(ExtractAction.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());
return actionsList;
}
@Override
public List<? extends Action> visit(final LocalFile d) {
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
List<Action> actionsList = new ArrayList<>();
actionsList.add(ExtractAction.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());
return actionsList;
}
@Override
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance());
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
List<Action> actionsList = new ArrayList<>();
actionsList.add(ExtractAction.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());
return actionsList;
}
@Override

View File

@ -31,7 +31,6 @@ import org.openide.util.NbBundle;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.examples.SampleExecutableIngestModuleFactory;
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.exif.ExifParserModuleFactory;
import org.sleuthkit.autopsy.modules.fileextmismatch.FileExtMismatchDetectorModuleFactory;
@ -63,7 +62,6 @@ final class IngestModuleFactoryLoader {
add("org.sleuthkit.autopsy.thunderbirdparser.EmailParserModuleFactory"); //NON-NLS
add(FileExtMismatchDetectorModuleFactory.class.getCanonicalName());
add(E01VerifierModuleFactory.class.getCanonicalName());
add(AndroidModuleFactory.class.getCanonicalName());
add(InterestingItemsIngestModuleFactory.class.getCanonicalName());
add(PhotoRecCarverIngestModuleFactory.class.getCanonicalName());
}

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

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

View File

@ -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();
}
}

View File

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

View File

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

View File

@ -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);
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2011-2015 Basis Technology Corp.
* Copyright 2011-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -25,6 +25,8 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.List;
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.usermodel.PictureData;
import org.apache.poi.hslf.usermodel.SlideShow;
@ -120,7 +122,7 @@ class ImageExtractor {
}
return false;
} 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;
}
}
@ -152,7 +154,7 @@ class ImageExtractor {
}
}
} 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;
}
switch (abstractFileExtractionFormat) {
@ -189,7 +191,7 @@ class ImageExtractor {
extractedImage.getCtime(), extractedImage.getCrtime(), extractedImage.getAtime(), extractedImage.getAtime(),
true, abstractFile, null, EmbeddedFileExtractorModuleFactory.getModuleName(), null, null, TskData.EncodingType.XOR1));
} 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()) {
@ -207,24 +209,24 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromDoc(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
HWPFDocument doc = null;
List<org.apache.poi.hwpf.usermodel.Picture> listOfAllPictures;
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) {
// instantiating POI containers throw RuntimeExceptions
logger.log(Level.WARNING, 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
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@ -237,15 +239,13 @@ class ImageExtractor {
if (outputFolderPath == null) {
return null;
}
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (org.apache.poi.hwpf.usermodel.Picture picture : listOfAllPictures) {
String fileName = picture.suggestFullFileName();
try {
data = picture.getContent();
} 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;
}
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
@ -265,21 +265,22 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromDocx(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
XWPFDocument docx = null;
List<XWPFPictureData> listOfAllPictures = null;
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) {
// instantiating POI containers throw RuntimeExceptions
logger.log(Level.WARNING, 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
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.docxContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@ -292,18 +293,15 @@ class ImageExtractor {
outputFolderPath = getOutputFolderPath(this.parentFileName);
}
if (outputFolderPath == null) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
return null;
}
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (XWPFPictureData xwpfPicture : listOfAllPictures) {
String fileName = xwpfPicture.getFileName();
try {
data = xwpfPicture.getData();
} 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;
}
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
@ -321,23 +319,22 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromPpt(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
SlideShow ppt = null;
PictureData[] listOfAllPictures = null;
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) {
// instantiating POI containers throw RuntimeExceptions
logger.log(Level.WARNING, 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
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@ -350,14 +347,13 @@ class ImageExtractor {
outputFolderPath = getOutputFolderPath(this.parentFileName);
}
if (outputFolderPath == null) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
return null;
}
// extract the images to the above initialized outputFolder.
// extraction path - outputFolder/image_number.ext
int i = 0;
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (PictureData pictureData : listOfAllPictures) {
@ -388,8 +384,6 @@ class ImageExtractor {
try {
data = pictureData.getData();
} 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;
}
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
@ -408,21 +402,22 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromPptx(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
XMLSlideShow pptx;
List<XSLFPictureData> listOfAllPictures = null;
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) {
// instantiating POI containers throw RuntimeExceptions
logger.log(Level.WARNING, 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
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.pptxContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@ -435,11 +430,10 @@ class ImageExtractor {
outputFolderPath = getOutputFolderPath(this.parentFileName);
}
if (outputFolderPath == null) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
return null;
}
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (XSLFPictureData xslsPicture : listOfAllPictures) {
@ -449,8 +443,6 @@ class ImageExtractor {
try {
data = xslsPicture.getData();
} 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;
}
writeExtractedImage(Paths.get(outputFolderPath, fileName).toString(), data);
@ -471,23 +463,22 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromXls(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
Workbook xls;
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
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) {
// 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
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
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;
}
@ -500,20 +491,17 @@ class ImageExtractor {
outputFolderPath = getOutputFolderPath(this.parentFileName);
}
if (outputFolderPath == null) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
return null;
}
int i = 0;
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension(); //NON-NLS
try {
data = pictureData.getData();
} 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;
}
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);
@ -533,22 +521,22 @@ class ImageExtractor {
* extracted.
*/
private List<ExtractedImage> extractImagesFromXlsx(AbstractFile af) {
List<ExtractedImage> listOfExtractedImages;
Workbook xlsx;
List<? extends org.apache.poi.ss.usermodel.PictureData> listOfAllPictures = null;
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) {
// instantiating POI containers throw RuntimeExceptions
logger.log(Level.WARNING, 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
logger.log(Level.SEVERE, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.xlsxContainer.init.err", af.getName()), ex); //NON-NLS
return null;
}
@ -561,20 +549,17 @@ class ImageExtractor {
outputFolderPath = getOutputFolderPath(this.parentFileName);
}
if (outputFolderPath == null) {
logger.log(Level.WARNING, NbBundle.getMessage(this.getClass(), "EmbeddedFileExtractorIngestModule.ImageExtractor.extractImageFrom.outputPath.exception.msg", af.getName())); //NON-NLS
return null;
}
int i = 0;
listOfExtractedImages = new ArrayList<>();
List<ExtractedImage> listOfExtractedImages = new ArrayList<>();
byte[] data = null;
for (org.apache.poi.ss.usermodel.PictureData pictureData : listOfAllPictures) {
String imageName = UNKNOWN_NAME_PREFIX + i + "." + pictureData.suggestFileExtension();
try {
data = pictureData.getData();
} catch (Exception ex) {
// 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;
}
writeExtractedImage(Paths.get(outputFolderPath, imageName).toString(), data);

View File

@ -1,15 +1,15 @@
/*
*
* Autopsy Forensic Browser
*
*
* Copyright 2013-2014 Basis Technology Corp.
*
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
*
* http://www.apache.org/licenses/LICENSE-2.0
*
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@ -36,7 +36,7 @@ import org.sleuthkit.autopsy.coreutils.PlatformUtil;
public final class ReportBranding implements ReportBrandingProviderI {
//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_FOOTER_PROP = "ReportFooter"; //NON-NLS
//default settings
@ -46,7 +46,7 @@ public final class ReportBranding implements ReportBrandingProviderI {
private static final String DEFAULT_REPORT_FOOTER = NbBundle
.getMessage(ReportBranding.class, "ReportBranding.defaultReportFooter.text");
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());
// this is static so that it can be set by another object
@ -130,7 +130,7 @@ public final class ReportBranding implements ReportBrandingProviderI {
@Override
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
ModuleSettings.setConfigSetting(MODULE_NAME, AGENCY_LOGO_PATH_PROP, path);
}

View File

@ -1,15 +1,15 @@
/*
*
* Autopsy Forensic Browser
*
*
* Copyright 2013 Basis Technology Corp.
*
*
* 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.

View File

@ -1,19 +1,19 @@
/*
*
* Autopsy Forensic Browser
*
*
* Copyright 2012-2014 Basis Technology Corp.
*
*
* Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com
* Project Contact/Architect: 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.
@ -32,6 +32,9 @@ import java.io.OutputStream;
import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException;
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.SimpleDateFormat;
import java.util.ArrayList;
@ -628,7 +631,7 @@ class ReportHTML implements TableReportModule {
}
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
// the number of rows.
rowCount = totalCount;
@ -759,7 +762,7 @@ class ReportHTML implements TableReportModule {
localFilePath.append(File.separator);
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.
File localFile = new File(localFilePath.toString());
if (!localFile.exists()) {
@ -856,7 +859,7 @@ class ReportHTML implements TableReportModule {
// use default Autopsy icon if custom icon is not set
iconPath = "favicon.ico";
} 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(
NbBundle.getMessage(this.getClass(), "ReportHTML.writeIndex.title", currentCase.getDisplayName())).append(
@ -949,9 +952,8 @@ class ReportHTML implements TableReportModule {
String agencyLogoPath = reportBranding.getAgencyLogoPath();
if (agencyLogoPath != null && !agencyLogoPath.isEmpty()) {
File from = new File(agencyLogoPath);
File to = new File(path);
FileUtil.copyFile(FileUtil.toFileObject(from), FileUtil.toFileObject(to), "agency_logo"); //NON-NLS
Path destinationPath = Paths.get(path);
Files.copy(Files.newInputStream(Paths.get(agencyLogoPath)), destinationPath.resolve(Paths.get(agencyLogoPath).getFileName())); //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
if (agencyLogoSet) {
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
}
final String align = agencyLogoSet ? "right" : "left"; //NON-NLS NON-NLS

View File

@ -156,7 +156,11 @@ public class SnapShotReportWriter {
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("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
}
@ -199,7 +203,7 @@ public class SnapShotReportWriter {
}
String agencyLogoPath = reportBranding.getAgencyLogoPath();
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

View File

@ -13,7 +13,7 @@
<div class="title">
{{#reportBranding.getAgencyLogoPath}}
<div class="left">
<img src="agency_logo.png" />
<img src="{{agencyLogoFileName}}" />
</div>
<div class="right">
{{/reportBranding.getAgencyLogoPath}}

View File

@ -234,7 +234,7 @@ public final class AutoIngestCasePanel extends JPanel {
try {
int selectedRow = casesTable.getSelectedRow();
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) {
return null;
@ -251,7 +251,7 @@ public final class AutoIngestCasePanel extends JPanel {
if (path != null) {
try {
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
casesTable.setRowSelectionInterval(row, row);
return;
@ -546,9 +546,10 @@ public final class AutoIngestCasePanel extends JPanel {
* @param evt -- The event that caused this to be called
*/
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()),
caseTableModel.getValueAt(casesTable.getSelectedRow(), COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
openCase(caseMetadataFilePath);
}//GEN-LAST:event_bnOpenActionPerformed
@ -587,7 +588,7 @@ public final class AutoIngestCasePanel extends JPanel {
}//GEN-LAST:event_rbWeeksItemStateChanged
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();
if (selectedRow >= 0 && selectedRow < rowCount) {
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
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()),
caseTableModel.getValueAt(casesTable.getSelectedRow(), COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
caseTableModel.getValueAt(modelRow, COLUMN_HEADERS.CASE.ordinal()) + CaseMetadata.getFileExtension());
openCase(caseMetadataFilePath);
}
}//GEN-LAST:event_casesTableMouseClicked

View File

@ -64,7 +64,6 @@ import javax.annotation.concurrent.ThreadSafe;
import org.openide.util.Lookup;
import org.sleuthkit.autopsy.casemodule.Case;
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.CaseMetadata;
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 {
Manifest manifest = currentJob.getManifest();
String caseDisplayName = manifest.getCaseName();
String caseName;
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()});
String caseName = manifest.getCaseName();
SYS_LOGGER.log(Level.INFO, "Opening case {0} for {2}", new Object[]{caseName, manifest.getFilePath()});
currentJob.setStage(AutoIngestJob.Stage.OPENING_CASE);
/*
* 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;
} 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) {
/*
* Deal with the unfortunate fact that
* 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 {
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()));
}
}
}

View File

@ -46,18 +46,12 @@ final class PathUtils {
* @return The path of the case folder, or null if it is not found.
*/
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());
if (!searchFolder.isDirectory()) {
return null;
}
Path caseFolderPath = null;
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(sanitizedCaseName));
String[] candidateFolders = searchFolder.list(new CaseFolderFilter(caseName));
long mostRecentModified = 0;
for (String candidateFolder : candidateFolders) {
File file = new File(candidateFolder);

View 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);
}
}
}
}

View File

@ -1,7 +1,7 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2013-16 Basis Technology Corp.
* Copyright 2013-2017 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org
*
* Licensed under the Apache License, Version 2.0 (the "License");
@ -21,6 +21,7 @@ package org.sleuthkit.autopsy.imagegallery.gui.drawableviews;
import com.google.common.eventbus.Subscribe;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.Optional;
import java.util.logging.Level;
import javafx.application.Platform;
@ -49,6 +50,7 @@ import javax.swing.SwingUtilities;
import org.controlsfx.control.action.ActionUtils;
import org.openide.util.Lookup;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.actions.Presenter;
import org.openide.windows.TopComponent;
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.CategorizeAction;
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.SwingMenuItemAdapter;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableAttribute;
import org.sleuthkit.autopsy.imagegallery.datamodel.DrawableFile;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
@ -184,6 +188,11 @@ public abstract class DrawableTileBase extends DrawableUIBase {
menuItems.add(CategorizeAction.getCategoriesMenu(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());
extractMenuItem.setOnAction(actionEvent -> {

View 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())

View 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()

View 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))

View 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())

View 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

View 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)

View 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

View 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

View 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())

View 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())

View File

@ -19,6 +19,8 @@
package org.sleuthkit.autopsy.keywordsearch;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
import java.util.List;
import javax.swing.Action;
import org.openide.nodes.FilterNode;
@ -26,14 +28,17 @@ import org.openide.nodes.Node;
import org.openide.nodes.Node.Property;
import org.openide.nodes.Sheet;
import org.openide.util.NbBundle;
import org.openide.util.Utilities;
import org.openide.util.lookup.Lookups;
import org.openide.util.lookup.ProxyLookup;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.ContentVisitor;
import org.sleuthkit.datamodel.DerivedFile;
@ -107,16 +112,23 @@ class KeywordSearchFilterNode extends FilterNode {
}
private List<Action> getFileActions() {
List<Action> actions = new ArrayList<>();
actions.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this));
actions.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
actions.add(null);
actions.add(ExtractAction.getInstance());
actions.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal()));
actions.add(null); // creates a menu separator
actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions());
return actions;
List<Action> actionsList = new ArrayList<>();
actionsList.add(new NewWindowViewAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.viewInNewWinActionLbl"), KeywordSearchFilterNode.this));
actionsList.add(new ExternalViewerAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.openExternViewActLbl"), getOriginal()));
actionsList.add(null);
actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction(NbBundle.getMessage(this.getClass(), "KeywordSearchFilterNode.getFileActions.searchSameMd5"), getOriginal()));
actionsList.add(null); // creates a menu separator
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());
return actionsList;
}
@Override

View File

@ -4,7 +4,7 @@ app.title=Autopsy
### lowercase version of above
app.name=${branding.token}
### 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=RELEASE
build.type=DEVELOPMENT

View File

@ -58,8 +58,7 @@ from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.datamodel import ContentUtils
from org.sleuthkit.autopsy.casemodule.services import Services
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
# '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):
self.context = context
# Throw an IngestModule.IngestModuleException exception if there was a problem setting up
# raise IngestModuleException("Oh No!")
# Where the analysis is done.
# 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
# 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):
# we don't know how much work there is yet
progressBar.switchToIndeterminate()
# This will work in 4.0.1 and beyond
# 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
fileManager = Case.getCurrentCase().getServices().getFileManager()
@ -124,7 +120,7 @@ class ContactsDbIngestModule(DataSourceIngestModule):
numFiles = len(files)
progressBar.switchToDeterminate(numFiles)
fileCount = 0;
fileCount = 0
for file in files:
# 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(),
ContactsDbIngestModuleFactory.moduleName, phone))
# This will work in 4.0.1 and beyond
#try:
# # index the artifact for keyword search
# blackboard.indexArtifact(art)
#except Blackboard.BlackboardException as e:
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
try:
# index the artifact for keyword search
blackboard.indexArtifact(art)
except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there are new artifacts
IngestServices.getInstance().fireModuleDataEvent(

View File

@ -95,7 +95,7 @@ class RunExeIngestModule(DataSourceIngestModule):
# Where any setup and configuration is done
# '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):
self.context = context
@ -108,9 +108,9 @@ class RunExeIngestModule(DataSourceIngestModule):
# Where the analysis is done.
# 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
# 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):
# we don't know how much work there will be

View File

@ -56,8 +56,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services
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
# 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
# '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.
def startUp(self, context):
self.filesFound = 0
@ -104,12 +103,11 @@ class FindBigRoundFilesIngestModule(FileIngestModule):
# 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.
# 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):
# This will work in 4.0.1 and beyond
# Use blackboard class to index blackboard artifacts for keyword search
# blackboard = Case.getCurrentCase().getServices().getBlackboard()
blackboard = Case.getCurrentCase().getServices().getBlackboard()
# Skip non-files
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")
art.addAttribute(att)
# This will work in 4.0.1 and beyond
#try:
# # index the artifact for keyword search
# blackboard.indexArtifact(art)
#except Blackboard.BlackboardException as e:
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
try:
# index the artifact for keyword search
blackboard.indexArtifact(art)
except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there is a new artifact
IngestServices.getInstance().fireModuleDataEvent(
ModuleDataEvent(FindBigRoundFilesIngestModuleFactory.moduleName,
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None));
BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT, None))
return IngestModule.ProcessResult.OK
# Where any shutdown code is run and resources are freed.
# TODO: Add any shutdown code that you need here.
def shutDown(self):
None
None

View File

@ -27,7 +27,7 @@
# ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
# 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.
# 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
# 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.
# 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):
# Open the output file.

View File

@ -29,7 +29,7 @@
# Simple data source-level ingest module for Autopsy.
# 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 inspect
@ -51,8 +51,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services
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
@ -95,32 +94,32 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
# Where any setup and configuration is done
# '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.
def startUp(self, context):
self.context = context
# 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.
# 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
# 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.
def process(self, dataSource, progressBar):
# we don't know how much work there is yet
progressBar.switchToIndeterminate()
# This will work in 4.0.1 and beyond
# 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
# files with the word "test"
# 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()
files = fileManager.findFiles(dataSource, "%test%")
@ -143,12 +142,11 @@ class SampleJythonDataSourceIngestModule(DataSourceIngestModule):
att = BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME, SampleJythonDataSourceIngestModuleFactory.moduleName, "Test file")
art.addAttribute(att)
# This will work in 4.0.1 and beyond
#try:
# # index the artifact for keyword search
# blackboard.indexArtifact(art)
#except Blackboard.BlackboardException as e:
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
try:
# index the artifact for keyword search
blackboard.indexArtifact(art)
except Blackboard.BlackboardException as e:
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
inputStream = ReadContentInputStream(file)

View File

@ -29,7 +29,7 @@
# Simple file-level ingest module for Autopsy.
# 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 inspect
@ -53,8 +53,7 @@ from org.sleuthkit.autopsy.coreutils import Logger
from org.sleuthkit.autopsy.casemodule import Case
from org.sleuthkit.autopsy.casemodule.services import Services
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
# 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
# '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.
def startUp(self, context):
self.filesFound = 0
@ -106,7 +105,7 @@ class SampleJythonFileIngestModule(FileIngestModule):
# 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.
# 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.
def process(self, file):
# Skip non-files
@ -115,9 +114,8 @@ class SampleJythonFileIngestModule(FileIngestModule):
(file.isFile() == False)):
return IngestModule.ProcessResult.OK
# This will work in 4.0.1 and beyond
# 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.
if file.getName().lower().endswith(".txt"):
@ -132,12 +130,11 @@ class SampleJythonFileIngestModule(FileIngestModule):
SampleJythonFileIngestModuleFactory.moduleName, "Text Files")
art.addAttribute(att)
# This will work in 4.0.1 and beyond
#try:
# # index the artifact for keyword search
# blackboard.indexArtifact(art)
#except Blackboard.BlackboardException as e:
# self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
try:
# index the artifact for keyword search
blackboard.indexArtifact(art)
except Blackboard.BlackboardException as e:
self.log(Level.SEVERE, "Error indexing artifact " + art.getDisplayName())
# Fire an event to notify the UI and others that there is a new artifact
IngestServices.getInstance().fireModuleDataEvent(
@ -171,4 +168,4 @@ class SampleJythonFileIngestModule(FileIngestModule):
message = IngestMessage.createMessage(
IngestMessage.MessageType.DATA, SampleJythonFileIngestModuleFactory.moduleName,
str(self.filesFound) + " files found")
ingestServices = IngestServices.getInstance().postMessage(message)
ingestServices = IngestServices.getInstance().postMessage(message)

View File

@ -35,7 +35,7 @@
# don't need a configuration UI, start with the other sample module.
#
# 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
@ -204,4 +204,3 @@ class SampleFileIngestModuleWithUISettingsPanel(IngestModuleIngestJobSettingsPan
# Return the settings used
def getSettings(self):
return self.local_settings

View File

@ -31,7 +31,7 @@
# Sample report module for Autopsy. Use as a starting point for new modules.
#
# 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
from java.lang import System
@ -69,7 +69,7 @@ class SampleGeneralReportModule(GeneralReportModuleAdapter):
# 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 '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):
# For an example, we write a file with the number of files created in the past 2 weeks