mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-12 07:56:16 +00:00
Merge remote-tracking branch 'upstream/develop' into hashdb_sqlite
This commit is contained in:
commit
a939f04b72
14
.gitattributes
vendored
Normal file
14
.gitattributes
vendored
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
*.java text diff=java
|
||||||
|
|
||||||
|
*.txt text
|
||||||
|
*.sh text
|
||||||
|
*.mf text
|
||||||
|
*.xml text
|
||||||
|
*.form text
|
||||||
|
*.properties text
|
||||||
|
*.html text diff=html
|
||||||
|
*.dox text
|
||||||
|
Doxyfile text
|
||||||
|
|
||||||
|
*.py text diff=python
|
||||||
|
*.pl text
|
@ -2,5 +2,8 @@ Changes to make to API when we are ready to make backward incompatible changes:
|
|||||||
|
|
||||||
- HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API.
|
- HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API.
|
||||||
- DataContentViewer.isPreferred does not need isSupported to be passed in
|
- DataContentViewer.isPreferred does not need isSupported to be passed in
|
||||||
- DataContentViewerHex and STrings can have the public setDataView methods removed in favor of the new private ones
|
- DataContentViewerHex and Strings can have the public setDataView methods removed in favor of the new private ones
|
||||||
Content.getUniquePath() shoudl not thrown TskException. We should deal with it in the method.
|
- Content.getUniquePath() should not thrown TskException. We should deal with it in the method.
|
||||||
|
- Make the list of events that Case fires off to be part of an enum to group them together (like IngestManager does).
|
||||||
|
- Sub-modules in RecentActivity have a bunch of public/protected variables that do not need to be. (i.e. ExtractRegistry.rrFullFound).
|
||||||
|
- Delete BrowserType enum and BrowserActivityType in RecentActivity.
|
||||||
|
23
BUILDING.txt
23
BUILDING.txt
@ -11,8 +11,7 @@ correct C libraries.
|
|||||||
STEPS:
|
STEPS:
|
||||||
1) Get Java Setup
|
1) Get Java Setup
|
||||||
|
|
||||||
1a) Download and install 32-bit version of JDK version 1.7 (32-bit is currently
|
1a) Download and install JDK version 1.7. You can now use 32-bit or 64-bit, but special work is needed to get The Sleuth Kit to compile as 64-bit. So, 32-bit is easier.
|
||||||
needed even if you have a 64-bit system).
|
|
||||||
|
|
||||||
Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support
|
Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support
|
||||||
(http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
(http://www.oracle.com/technetwork/java/javase/downloads/index.html).
|
||||||
@ -26,7 +25,8 @@ Note: Netbeans IDE is not required to build and run Autopsy,
|
|||||||
but it is a recommended IDE to use for development of Autopsy modules.
|
but it is a recommended IDE to use for development of Autopsy modules.
|
||||||
|
|
||||||
1d) (optional) If you are going to package Autopsy, then you'll also
|
1d) (optional) If you are going to package Autopsy, then you'll also
|
||||||
need to set JRE_HOME to the root JRE directory.
|
need to set JRE_HOME_32 to the root 32-bit JRE directory and/or JRE_HOME_64
|
||||||
|
to the root 64-bit JRE directory.
|
||||||
|
|
||||||
1e) (optional) For some Autopsy features to be functional, you need to add java executable to the system PATH.
|
1e) (optional) For some Autopsy features to be functional, you need to add java executable to the system PATH.
|
||||||
|
|
||||||
@ -37,6 +37,9 @@ need to set JRE_HOME to the root JRE directory.
|
|||||||
later). All you need is the dll file. Note that you will get a
|
later). All you need is the dll file. Note that you will get a
|
||||||
launching error if you use libewf 1.
|
launching error if you use libewf 1.
|
||||||
- http://sourceforge.net/projects/libewf/
|
- http://sourceforge.net/projects/libewf/
|
||||||
|
If you want to build the 64-bit version of The Sleuth Kit, download
|
||||||
|
our 64-bit version of libewf:
|
||||||
|
- https://github.com/sleuthkit/libewf_64bit
|
||||||
|
|
||||||
2b) Set LIBEWF_HOME environment variable to root directory of LIBEWF
|
2b) Set LIBEWF_HOME environment variable to root directory of LIBEWF
|
||||||
|
|
||||||
@ -97,13 +100,13 @@ BACKGROUND:
|
|||||||
Here are some notes to shed some light on what is going on during
|
Here are some notes to shed some light on what is going on during
|
||||||
the build process.
|
the build process.
|
||||||
|
|
||||||
- NetBeans uses ant to build Autopsy. The build target locates TSK
|
- The Sleuth Kit Java datamodel JAR file has native libraries
|
||||||
(and LIBEWF) based on the environment variables and copies the
|
that are copied into it.
|
||||||
needed JAR and library files into the DataModel module in the Autopsy
|
|
||||||
project (see build-unix.xml and build-windows.xml in the root
|
- NetBeans uses ant to build Autopsy. The build target copies the
|
||||||
directory for details). If you want to use the debug version of
|
TSK datamodel JAR file into the project. If you want to use the
|
||||||
the TSK dll, then edit the copy line in the build-windows.xml file
|
debug version of the TSK dll, then there is a different ant target
|
||||||
to copy from the Debug folder.
|
in TSK to copy the debug versions of the dlls.
|
||||||
|
|
||||||
- On a Windows system, the ant target copies all needed libraries
|
- On a Windows system, the ant target copies all needed libraries
|
||||||
to the autopsy folder. On a Unix system, the ant taget copies only
|
to the autopsy folder. On a Unix system, the ant taget copies only
|
||||||
|
@ -191,6 +191,7 @@
|
|||||||
</dependency>
|
</dependency>
|
||||||
</module-dependencies>
|
</module-dependencies>
|
||||||
<public-packages>
|
<public-packages>
|
||||||
|
<package>org.sleuthkit.autopsy.actions</package>
|
||||||
<package>org.sleuthkit.autopsy.casemodule</package>
|
<package>org.sleuthkit.autopsy.casemodule</package>
|
||||||
<package>org.sleuthkit.autopsy.casemodule.services</package>
|
<package>org.sleuthkit.autopsy.casemodule.services</package>
|
||||||
<package>org.sleuthkit.autopsy.core</package>
|
<package>org.sleuthkit.autopsy.core</package>
|
||||||
|
69
Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
Executable file
69
Core/src/org/sleuthkit/autopsy/actions/AddBlackboardArtifactTagAction.java
Executable file
@ -0,0 +1,69 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.util.Collection;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to apply tags to blackboard artifacts.
|
||||||
|
*/
|
||||||
|
public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||||
|
// 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 AddBlackboardArtifactTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized AddBlackboardArtifactTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new AddBlackboardArtifactTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AddBlackboardArtifactTagAction() {
|
||||||
|
super("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getActionDisplayName() {
|
||||||
|
return Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addTag(TagName tagName, String comment) {
|
||||||
|
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
||||||
|
for (BlackboardArtifact artifact : selectedArtifacts) {
|
||||||
|
try {
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(AddBlackboardArtifactTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to tag " + artifact.getDisplayName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
99
Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
Executable file
99
Core/src/org/sleuthkit/autopsy/actions/AddContentTagAction.java
Executable file
@ -0,0 +1,99 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.util.Collection;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
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.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to apply tags to content.
|
||||||
|
*/
|
||||||
|
public class AddContentTagAction extends AddTagAction {
|
||||||
|
// 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 AddContentTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized AddContentTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new AddContentTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private AddContentTagAction() {
|
||||||
|
super("");
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected String getActionDisplayName() {
|
||||||
|
return Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void addTag(TagName tagName, String comment) {
|
||||||
|
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
|
||||||
|
for (AbstractFile file : selectedFiles) {
|
||||||
|
try {
|
||||||
|
// Handle the special cases of current (".") and parent ("..") directory entries.
|
||||||
|
if (file.getName().equals(".")) {
|
||||||
|
Content parentFile = file.getParent();
|
||||||
|
if (parentFile instanceof AbstractFile) {
|
||||||
|
file = (AbstractFile)parentFile;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (file.getName().equals("..")) {
|
||||||
|
Content parentFile = file.getParent();
|
||||||
|
if (parentFile instanceof AbstractFile) {
|
||||||
|
parentFile = (AbstractFile)((AbstractFile)parentFile).getParent();
|
||||||
|
if (parentFile instanceof AbstractFile) {
|
||||||
|
file = (AbstractFile)parentFile;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to tag " + parentFile.getName() + ", not a regular file.", "Cannot Apply Tag", JOptionPane.WARNING_MESSAGE);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error tagging result", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to tag " + file.getName() + ".", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
148
Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
Executable file
148
Core/src/org/sleuthkit/autopsy/actions/AddTagAction.java
Executable file
@ -0,0 +1,148 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.awt.event.ActionListener;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.JMenu;
|
||||||
|
import javax.swing.JMenuItem;
|
||||||
|
import org.openide.util.actions.Presenter;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* An abstract base class for Actions that allow users to tag SleuthKit data
|
||||||
|
* model objects.
|
||||||
|
*/
|
||||||
|
abstract class AddTagAction extends TagAction implements Presenter.Popup {
|
||||||
|
private static final String NO_COMMENT = "";
|
||||||
|
|
||||||
|
AddTagAction(String menuText) {
|
||||||
|
super(menuText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public JMenuItem getPopupPresenter() {
|
||||||
|
return new TagMenu();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doAction(ActionEvent event) {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to allow derived classes to provide a string for for a
|
||||||
|
* menu item label.
|
||||||
|
*/
|
||||||
|
abstract protected String getActionDisplayName();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Template method to allow derived classes to add the indicated tag and
|
||||||
|
* comment to one or more a SleuthKit data model objects.
|
||||||
|
*/
|
||||||
|
abstract protected void addTag(TagName tagName, String comment);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
// @@@ This user interface has some significant usability issues and needs
|
||||||
|
// to be reworked.
|
||||||
|
private class TagMenu extends JMenu {
|
||||||
|
TagMenu() {
|
||||||
|
super(getActionDisplayName());
|
||||||
|
|
||||||
|
// Get the current set of tag names.
|
||||||
|
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||||
|
List<TagName> tagNames = null;
|
||||||
|
try {
|
||||||
|
tagNames = tagsManager.getAllTagNames();
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a "Quick Tag" sub-menu.
|
||||||
|
JMenu quickTagMenu = new JMenu("Quick Tag");
|
||||||
|
add(quickTagMenu);
|
||||||
|
|
||||||
|
// 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 != tagNames && !tagNames.isEmpty()) {
|
||||||
|
for (final TagName tagName : tagNames) {
|
||||||
|
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
|
||||||
|
tagNameItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
addTag(tagName, NO_COMMENT);
|
||||||
|
refreshDirectoryTree();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quickTagMenu.add(tagNameItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
JMenuItem empty = new JMenuItem("No tags");
|
||||||
|
empty.setEnabled(false);
|
||||||
|
quickTagMenu.add(empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
quickTagMenu.addSeparator();
|
||||||
|
|
||||||
|
// The "Quick Tag" menu also gets an "Choose Tag..." menu item.
|
||||||
|
// Selecting this item initiates a dialog that can be used to create
|
||||||
|
// or select a tag name and adds a tag with the resulting name.
|
||||||
|
JMenuItem newTagMenuItem = new JMenuItem("New Tag...");
|
||||||
|
newTagMenuItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
TagName tagName = GetTagNameDialog.doDialog();
|
||||||
|
if (tagName != null) {
|
||||||
|
addTag(tagName, NO_COMMENT);
|
||||||
|
refreshDirectoryTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
quickTagMenu.add(newTagMenuItem);
|
||||||
|
|
||||||
|
// Create a "Choose Tag and Comment..." menu item. Selecting this item initiates
|
||||||
|
// a dialog that can be used to create or select a tag name with an
|
||||||
|
// optional comment and adds a tag with the resulting name.
|
||||||
|
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment...");
|
||||||
|
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
GetTagNameAndCommentDialog.TagNameAndComment tagNameAndComment = GetTagNameAndCommentDialog.doDialog();
|
||||||
|
if (null != tagNameAndComment) {
|
||||||
|
addTag(tagNameAndComment.getTagName(), tagNameAndComment.getComment());
|
||||||
|
refreshDirectoryTree();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
add(tagAndCommentItem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
16
Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
Executable file
16
Core/src/org/sleuthkit/autopsy/actions/Bundle.properties
Executable file
@ -0,0 +1,16 @@
|
|||||||
|
GetTagNameDialog.tagNameField.text=
|
||||||
|
GetTagNameDialog.cancelButton.text=Cancel
|
||||||
|
GetTagNameDialog.okButton.text=OK
|
||||||
|
GetTagNameDialog.preexistingLabel.text=Pre-existing Tags:
|
||||||
|
GetTagNameDialog.newTagPanel.border.title=New Tag
|
||||||
|
GetTagNameDialog.tagNameLabel.text=Tag Name:
|
||||||
|
GetTagNameAndCommentDialog.newTagButton.text=New Tag
|
||||||
|
GetTagNameAndCommentDialog.okButton.text=OK
|
||||||
|
GetTagNameAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
|
||||||
|
GetTagNameAndCommentDialog.commentText.text=
|
||||||
|
GetTagNameAndCommentDialog.commentLabel.text=Comment:
|
||||||
|
# To change this template, choose Tools | Templates
|
||||||
|
# and open the template in the editor.
|
||||||
|
GetTagNameAndCommentDialog.cancelButton.text=Cancel
|
||||||
|
GetTagNameAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
||||||
|
GetTagNameAndCommentDialog.tagLabel.text=Tag:
|
@ -0,0 +1,67 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to delete tags applied to blackboard artifacts.
|
||||||
|
*/
|
||||||
|
public class DeleteBlackboardArtifactTagAction extends TagAction {
|
||||||
|
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||||
|
|
||||||
|
// 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 DeleteBlackboardArtifactTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized DeleteBlackboardArtifactTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new DeleteBlackboardArtifactTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeleteBlackboardArtifactTagAction() {
|
||||||
|
super(MENU_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doAction(ActionEvent event) {
|
||||||
|
Collection<? extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
|
||||||
|
for (BlackboardArtifactTag tag : selectedTags) {
|
||||||
|
try {
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
@ -0,0 +1,66 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.JOptionPane;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this Action allow users to delete tags applied to content.
|
||||||
|
*/
|
||||||
|
public class DeleteContentTagAction extends TagAction {
|
||||||
|
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||||
|
|
||||||
|
// 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 DeleteContentTagAction instance;
|
||||||
|
|
||||||
|
public static synchronized DeleteContentTagAction getInstance() {
|
||||||
|
if (null == instance) {
|
||||||
|
instance = new DeleteContentTagAction();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
private DeleteContentTagAction() {
|
||||||
|
super(MENU_TEXT);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void doAction(ActionEvent e) {
|
||||||
|
Collection<? extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
|
||||||
|
for (ContentTag tag : selectedTags) {
|
||||||
|
try {
|
||||||
|
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -78,7 +78,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="okButton">
|
<Component class="javax.swing.JButton" name="okButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
@ -91,7 +91,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="cancelButton">
|
<Component class="javax.swing.JButton" name="cancelButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
@ -104,7 +104,7 @@
|
|||||||
<StringArray count="0"/>
|
<StringArray count="0"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
@ -114,31 +114,31 @@
|
|||||||
<Component class="javax.swing.JLabel" name="tagLabel">
|
<Component class="javax.swing.JLabel" name="tagLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JLabel" name="commentLabel">
|
<Component class="javax.swing.JLabel" name="commentLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="commentText">
|
<Component class="javax.swing.JTextField" name="commentText">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JButton" name="newTagButton">
|
<Component class="javax.swing.JButton" name="newTagButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
@ -16,11 +16,13 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.directorytree;
|
package org.sleuthkit.autopsy.actions;
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.TreeSet;
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
import javax.swing.ActionMap;
|
import javax.swing.ActionMap;
|
||||||
import javax.swing.InputMap;
|
import javax.swing.InputMap;
|
||||||
@ -29,28 +31,28 @@ import javax.swing.JDialog;
|
|||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.KeyStroke;
|
import javax.swing.KeyStroke;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
public class GetTagNameAndCommentDialog extends JDialog {
|
||||||
* Tag dialog for tagging files and results. User enters an optional comment.
|
private static final String NO_TAG_NAMES_MESSAGE = "No Tags";
|
||||||
*/
|
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||||
public class TagAndCommentDialog extends JDialog {
|
private TagNameAndComment tagNameAndComment = null;
|
||||||
|
|
||||||
private static final String NO_TAG_MESSAGE = "No Tags";
|
public static class TagNameAndComment {
|
||||||
private String tagName = "";
|
private TagName tagName;
|
||||||
private String comment = "";
|
|
||||||
|
|
||||||
public static class CommentedTag {
|
|
||||||
private String name;
|
|
||||||
private String comment;
|
private String comment;
|
||||||
|
|
||||||
CommentedTag(String name, String comment) {
|
private TagNameAndComment(TagName tagName, String comment) {
|
||||||
this.name = name;
|
this.tagName = tagName;
|
||||||
this.comment = comment;
|
this.comment = comment;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getName() {
|
public TagName getTagName() {
|
||||||
return name;
|
return tagName;
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getComment() {
|
public String getComment() {
|
||||||
@ -58,25 +60,16 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public static CommentedTag doDialog() {
|
public static TagNameAndComment doDialog() {
|
||||||
TagAndCommentDialog dialog = new TagAndCommentDialog();
|
GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog();
|
||||||
if (!dialog.tagName.isEmpty()) {
|
return dialog.tagNameAndComment;
|
||||||
return new CommentedTag(dialog.tagName, dialog.comment);
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
private GetTagNameAndCommentDialog() {
|
||||||
* Creates new form TagDialog
|
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||||
*/
|
|
||||||
private TagAndCommentDialog() {
|
|
||||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
// Close the dialog when Esc is pressed
|
// Set up the dialog to close when Esc is pressed.
|
||||||
String cancelName = "cancel";
|
String cancelName = "cancel";
|
||||||
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||||
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||||
@ -88,23 +81,29 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
// get the current list of tag names
|
// Populate the combo box with the available tag names and save the
|
||||||
TreeSet<String> tags = Tags.getAllTagNames();
|
// tag name DTOs to be enable to return the one the user selects.
|
||||||
|
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||||
// if there are no tags, add the NO_TAG_MESSAGE
|
List<TagName> currentTagNames = null;
|
||||||
if (tags.isEmpty()) {
|
try {
|
||||||
tags.add(NO_TAG_MESSAGE);
|
currentTagNames = tagsManager.getAllTagNames();
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
if (null != currentTagNames && currentTagNames.isEmpty()) {
|
||||||
|
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
for (TagName tagName : currentTagNames) {
|
||||||
|
tagNames.put(tagName.getDisplayName(), tagName);
|
||||||
|
tagCombo.addItem(tagName.getDisplayName());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// add the tags to the combo box
|
// Center and show the dialog box.
|
||||||
for (String tag : tags) {
|
|
||||||
tagCombo.addItem(tag);
|
|
||||||
}
|
|
||||||
|
|
||||||
//center it
|
|
||||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||||
|
setVisible(true);
|
||||||
setVisible(true); // blocks
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -130,30 +129,30 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.okButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.okButton.text")); // NOI18N
|
||||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
okButtonActionPerformed(evt);
|
okButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.cancelButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.cancelButton.text")); // NOI18N
|
||||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
cancelButtonActionPerformed(evt);
|
cancelButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagCombo.toolTipText")); // NOI18N
|
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagCombo.toolTipText")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagLabel.text")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N
|
||||||
|
|
||||||
commentText.setText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.text")); // NOI18N
|
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
|
||||||
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N
|
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.newTagButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N
|
||||||
newTagButton.addActionListener(new java.awt.event.ActionListener() {
|
newTagButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
newTagButtonActionPerformed(evt);
|
newTagButtonActionPerformed(evt);
|
||||||
@ -212,27 +211,26 @@ public class TagAndCommentDialog extends JDialog {
|
|||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||||
tagName = (String)tagCombo.getSelectedItem();
|
tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText());
|
||||||
comment = commentText.getText();
|
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_okButtonActionPerformed
|
}//GEN-LAST:event_okButtonActionPerformed
|
||||||
|
|
||||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||||
|
tagNameAndComment = null;
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||||
|
|
||||||
/**
|
|
||||||
* Closes the dialog
|
|
||||||
*/
|
|
||||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
||||||
|
tagNameAndComment = null;
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_closeDialog
|
}//GEN-LAST:event_closeDialog
|
||||||
|
|
||||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
TagName newTagName = GetTagNameDialog.doDialog();
|
||||||
if (newTagName != null) {
|
if (newTagName != null) {
|
||||||
tagCombo.addItem(newTagName);
|
tagNames.put(newTagName.getDisplayName(), newTagName);
|
||||||
tagCombo.setSelectedItem(newTagName);
|
tagCombo.addItem(newTagName.getDisplayName());
|
||||||
|
tagCombo.setSelectedItem(newTagName.getDisplayName());
|
||||||
}
|
}
|
||||||
}//GEN-LAST:event_newTagButtonActionPerformed
|
}//GEN-LAST:event_newTagButtonActionPerformed
|
||||||
|
|
@ -72,7 +72,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="cancelButton">
|
<Component class="javax.swing.JButton" name="cancelButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
@ -82,7 +82,7 @@
|
|||||||
<Component class="javax.swing.JButton" name="okButton">
|
<Component class="javax.swing.JButton" name="okButton">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
||||||
@ -124,7 +124,7 @@
|
|||||||
<Component class="javax.swing.JLabel" name="preexistingLabel">
|
<Component class="javax.swing.JLabel" name="preexistingLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
@ -133,7 +133,7 @@
|
|||||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||||
<TitledBorder title="New Tag">
|
<TitledBorder title="New Tag">
|
||||||
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</TitledBorder>
|
</TitledBorder>
|
||||||
</Border>
|
</Border>
|
||||||
</Property>
|
</Property>
|
||||||
@ -168,14 +168,14 @@
|
|||||||
<Component class="javax.swing.JLabel" name="tagNameLabel">
|
<Component class="javax.swing.JLabel" name="tagNameLabel">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JTextField" name="tagNameField">
|
<Component class="javax.swing.JTextField" name="tagNameField">
|
||||||
<Properties>
|
<Properties>
|
||||||
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
|
||||||
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
<Events>
|
<Events>
|
@ -16,72 +16,130 @@
|
|||||||
* See the License for the specific language governing permissions and
|
* See the License for the specific language governing permissions and
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.directorytree;
|
package org.sleuthkit.autopsy.actions;
|
||||||
|
|
||||||
import java.awt.Dimension;
|
import java.awt.event.ActionEvent;
|
||||||
import java.awt.Toolkit;
|
|
||||||
import java.awt.event.KeyEvent;
|
import java.awt.event.KeyEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.HashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.ActionMap;
|
||||||
|
import javax.swing.InputMap;
|
||||||
|
import javax.swing.JComponent;
|
||||||
import javax.swing.JDialog;
|
import javax.swing.JDialog;
|
||||||
import javax.swing.JFrame;
|
import javax.swing.JFrame;
|
||||||
import javax.swing.JOptionPane;
|
import javax.swing.JOptionPane;
|
||||||
|
import javax.swing.KeyStroke;
|
||||||
import javax.swing.table.AbstractTableModel;
|
import javax.swing.table.AbstractTableModel;
|
||||||
import org.openide.util.ImageUtilities;
|
import org.openide.util.ImageUtilities;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
import org.openide.windows.WindowManager;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
public class CreateTagDialog extends JDialog {
|
public class GetTagNameDialog extends JDialog {
|
||||||
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||||
private static String newTagName;
|
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||||
|
private TagName tagName = null;
|
||||||
|
|
||||||
/**
|
public static TagName doDialog() {
|
||||||
* Creates new form CreateTagDialog
|
GetTagNameDialog dialog = new GetTagNameDialog();
|
||||||
*/
|
return dialog.tagName;
|
||||||
private CreateTagDialog(JFrame parent) {
|
|
||||||
super(parent, true);
|
|
||||||
init();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getNewTagNameDialog(JFrame parent) {
|
private GetTagNameDialog() {
|
||||||
new CreateTagDialog(parent);
|
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||||
return newTagName;
|
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
||||||
}
|
|
||||||
|
|
||||||
private void init() {
|
|
||||||
|
|
||||||
setTitle("Create a new tag");
|
|
||||||
|
|
||||||
initComponents();
|
initComponents();
|
||||||
|
|
||||||
tagsTable.setModel(new TagsTableModel());
|
// Set up the dialog to close when Esc is pressed.
|
||||||
tagsTable.setTableHeader(null);
|
String cancelName = "cancel";
|
||||||
|
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||||
|
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
|
||||||
|
ActionMap actionMap = getRootPane().getActionMap();
|
||||||
|
actionMap.put(cancelName, new AbstractAction() {
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent e) {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
//completely disable selections
|
// Get the current set of tag names and hash them for a speedy lookup in
|
||||||
|
// case the user chooses an existing tag name from the tag names table.
|
||||||
|
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||||
|
List<TagName> currentTagNames = null;
|
||||||
|
try {
|
||||||
|
currentTagNames = tagsManager.getAllTagNames();
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
if (null != currentTagNames) {
|
||||||
|
for (TagName name : currentTagNames) {
|
||||||
|
this.tagNames.put(name.getDisplayName(), name);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
currentTagNames = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Populate the tag names table.
|
||||||
|
tagsTable.setModel(new TagsTableModel(currentTagNames));
|
||||||
|
tagsTable.setTableHeader(null);
|
||||||
tagsTable.setCellSelectionEnabled(false);
|
tagsTable.setCellSelectionEnabled(false);
|
||||||
tagsTable.setFocusable(false);
|
tagsTable.setFocusable(false);
|
||||||
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
|
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
|
||||||
|
|
||||||
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
// Center and show the dialog box.
|
||||||
|
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||||
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
|
setVisible(true);
|
||||||
// set the popUp window / JFrame
|
|
||||||
int w = this.getSize().width;
|
|
||||||
int h = this.getSize().height;
|
|
||||||
|
|
||||||
// set the location of the popUp Window on the center of the screen
|
|
||||||
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
|
|
||||||
setVisible(true); //blocks
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean containsIllegalCharacters(String content) {
|
private boolean containsIllegalCharacters(String content) {
|
||||||
if ((content.contains("\\") || content.contains(":") || content.contains("*")
|
return (content.contains("\\")||
|
||||||
|| content.contains("?") || content.contains("\"") || content.contains("<")
|
content.contains(":") ||
|
||||||
|| content.contains(">") || content.contains("|"))) {
|
content.contains("*") ||
|
||||||
return true;
|
content.contains("?") ||
|
||||||
|
content.contains("\"")||
|
||||||
|
content.contains("<") ||
|
||||||
|
content.contains(">") ||
|
||||||
|
content.contains("|"));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private class TagsTableModel extends AbstractTableModel {
|
||||||
|
private final ArrayList<TagName> tagNames = new ArrayList<>();
|
||||||
|
|
||||||
|
TagsTableModel(List<TagName> tagNames) {
|
||||||
|
for (TagName tagName : tagNames) {
|
||||||
|
this.tagNames.add(tagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getRowCount() {
|
||||||
|
return tagNames.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getColumnCount() {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getValueAt(int rowIndex, int columnIndex) {
|
||||||
|
return tagNames.get(rowIndex).getDisplayName();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This method is called from within the constructor to initialize the form.
|
* This method is called from within the constructor to initialize the form.
|
||||||
* WARNING: Do NOT modify this code. The content of this method is always
|
* WARNING: Do NOT modify this code. The content of this method is always
|
||||||
@ -107,14 +165,14 @@ public class CreateTagDialog extends JDialog {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.cancelButton.text")); // NOI18N
|
||||||
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
cancelButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
cancelButtonActionPerformed(evt);
|
cancelButtonActionPerformed(evt);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.okButton.text")); // NOI18N
|
||||||
okButton.addActionListener(new java.awt.event.ActionListener() {
|
okButton.addActionListener(new java.awt.event.ActionListener() {
|
||||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
okButtonActionPerformed(evt);
|
okButtonActionPerformed(evt);
|
||||||
@ -137,13 +195,13 @@ public class CreateTagDialog extends JDialog {
|
|||||||
tagsTable.setTableHeader(null);
|
tagsTable.setTableHeader(null);
|
||||||
jScrollPane1.setViewportView(tagsTable);
|
jScrollPane1.setViewportView(tagsTable);
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.preexistingLabel.text")); // NOI18N
|
||||||
|
|
||||||
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N
|
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.newTagPanel.border.title"))); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameLabel.text")); // NOI18N
|
||||||
|
|
||||||
tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N
|
tagNameField.setText(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameField.text")); // NOI18N
|
||||||
tagNameField.addKeyListener(new java.awt.event.KeyAdapter() {
|
tagNameField.addKeyListener(new java.awt.event.KeyAdapter() {
|
||||||
public void keyReleased(java.awt.event.KeyEvent evt) {
|
public void keyReleased(java.awt.event.KeyEvent evt) {
|
||||||
tagNameFieldKeyReleased(evt);
|
tagNameFieldKeyReleased(evt);
|
||||||
@ -211,21 +269,40 @@ public class CreateTagDialog extends JDialog {
|
|||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||||
newTagName = null;
|
tagName = null;
|
||||||
dispose();
|
dispose();
|
||||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||||
|
|
||||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||||
String tagName = tagNameField.getText();
|
String tagDisplayName = tagNameField.getText();
|
||||||
if (tagName.isEmpty()) {
|
if (tagDisplayName.isEmpty()) {
|
||||||
JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE);
|
||||||
} else if (containsIllegalCharacters(tagName)) {
|
}
|
||||||
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |",
|
else if (containsIllegalCharacters(tagDisplayName)) {
|
||||||
"Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
||||||
} else {
|
}
|
||||||
newTagName = tagName;
|
else {
|
||||||
|
tagName = tagNames.get(tagDisplayName);
|
||||||
|
if (tagName == null) {
|
||||||
|
try {
|
||||||
|
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
|
||||||
dispose();
|
dispose();
|
||||||
}
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
tagName = null;
|
||||||
|
}
|
||||||
|
catch (TagsManager.TagNameAlreadyExistsException ex) {
|
||||||
|
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
|
||||||
|
JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE);
|
||||||
|
tagName = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
dispose();
|
||||||
|
}
|
||||||
|
}
|
||||||
}//GEN-LAST:event_okButtonActionPerformed
|
}//GEN-LAST:event_okButtonActionPerformed
|
||||||
|
|
||||||
private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased
|
private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased
|
||||||
@ -251,32 +328,5 @@ public class CreateTagDialog extends JDialog {
|
|||||||
private javax.swing.JTable tagsTable;
|
private javax.swing.JTable tagsTable;
|
||||||
// End of variables declaration//GEN-END:variables
|
// End of variables declaration//GEN-END:variables
|
||||||
|
|
||||||
private class TagsTableModel extends AbstractTableModel {
|
|
||||||
List<String> tagNames;
|
|
||||||
|
|
||||||
TagsTableModel() {
|
|
||||||
tagNames = new ArrayList<>(Tags.getAllTagNames());
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getRowCount() {
|
|
||||||
return tagNames.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isCellEditable(int rowIndex, int columnIndex) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getColumnCount() {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getValueAt(int rowIndex, int columnIndex) {
|
|
||||||
return tagNames.get(rowIndex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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 javax.swing.AbstractAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Abstract base class for Actions involving tags.
|
||||||
|
*/
|
||||||
|
public abstract class TagAction extends AbstractAction {
|
||||||
|
public TagAction(String menuText) {
|
||||||
|
super(menuText);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void actionPerformed(ActionEvent event) {
|
||||||
|
doAction(event);
|
||||||
|
refreshDirectoryTree();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived classes must implement this Template Method for actionPerformed().
|
||||||
|
* @param event ActionEvent object passed to actionPerformed()
|
||||||
|
*/
|
||||||
|
abstract protected void doAction(ActionEvent event);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Derived classes should call this method any time a tag is created, updated
|
||||||
|
* or deleted outside of an actionPerformed() call.
|
||||||
|
*/
|
||||||
|
protected void refreshDirectoryTree() {
|
||||||
|
// The way the "directory tree" currently works, a new tags sub-tree
|
||||||
|
// needs to be made to reflect the results of invoking tag Actions. The
|
||||||
|
// way to do this is to call DirectoryTreeTopComponent.refreshTree(),
|
||||||
|
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
|
||||||
|
// for the RootContentChildren object that is the child factory for the
|
||||||
|
// ResultsNode that is the root of the tags sub-tree. There is a switch
|
||||||
|
// statement in RootContentChildren.refreshKeys() that maps both
|
||||||
|
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
|
||||||
|
// to making a call to refreshKey(TagsNodeKey).
|
||||||
|
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||||
|
}
|
||||||
|
}
|
@ -109,6 +109,71 @@ public class Case implements SleuthkitCase.ErrorObserver {
|
|||||||
// pcs is initialized in CaseListener constructor
|
// pcs is initialized in CaseListener constructor
|
||||||
private static final PropertyChangeSupport pcs = new PropertyChangeSupport(Case.class);
|
private static final PropertyChangeSupport pcs = new PropertyChangeSupport(Case.class);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Events that the case module will fire. Event listeners can get the event
|
||||||
|
* name by using String returned by toString() method on a specific event.
|
||||||
|
*/
|
||||||
|
/* @@@ BC: I added this as a place holder for what I want this to be, but
|
||||||
|
* this is not the time to change it. We'll start using this at a major release
|
||||||
|
* version.
|
||||||
|
*/
|
||||||
|
private enum CaseModuleEvent_DoNotUse {
|
||||||
|
/**
|
||||||
|
* Property name that indicates the name of the current case has changed.
|
||||||
|
* Fired with the case is renamed, and when the current case is
|
||||||
|
* opened/closed/changed. The value is a String: the name of the case. The
|
||||||
|
* empty string ("") is used for no open case.
|
||||||
|
*/
|
||||||
|
// @@@ BC: I propose that this is no longer called for case open/close.
|
||||||
|
CASE_NAME("caseName"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property name that indicates the number of the current case has changed.
|
||||||
|
* Fired with the case number is changed. The value is an int: the number of
|
||||||
|
* the case. -1 is used for no case number set.
|
||||||
|
*/
|
||||||
|
CASE_NUMBER("caseNumber"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property name that indicates the examiner of the current case has
|
||||||
|
* changed. Fired with the case examiner is changed. The value is a String:
|
||||||
|
* the name of the examiner. The empty string ("") is used for no examiner
|
||||||
|
* set.
|
||||||
|
*/
|
||||||
|
CASE_EXAMINER("caseExaminer"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property name that indicates a new data source (image, disk or local
|
||||||
|
* file) has been added to the current case. The new value is the
|
||||||
|
* newly-added instance of the new data source, and the old value is always
|
||||||
|
* null.
|
||||||
|
*/
|
||||||
|
CASE_ADD_DATA_SOURCE("addDataSource"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property name that indicates a data source has been removed from the
|
||||||
|
* current case. The "old value" is the (int) content ID of the data source
|
||||||
|
* that was removed, the new value is the instance of the data source.
|
||||||
|
*/
|
||||||
|
CASE_DEL_DATA_SOURCE("removeDataSource"),
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Property name that indicates the currently open case has changed. The new
|
||||||
|
* value is the instance of the opened Case, or null if there is no open
|
||||||
|
* case. The old value is the instance of the closed Case, or null if there
|
||||||
|
* was no open case.
|
||||||
|
*/
|
||||||
|
CASE_CURRENT_CASE("currentCase");
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
CaseModuleEvent_DoNotUse(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
|
@ -30,7 +30,7 @@
|
|||||||
</Group>
|
</Group>
|
||||||
<Group type="102" alignment="0" attributes="0">
|
<Group type="102" alignment="0" attributes="0">
|
||||||
<Component id="caseNameLabel" min="-2" max="-2" attributes="0"/>
|
<Component id="caseNameLabel" min="-2" max="-2" attributes="0"/>
|
||||||
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/>
|
<EmptySpace max="32767" attributes="0"/>
|
||||||
<Component id="caseNameTextField" min="-2" pref="296" max="-2" attributes="0"/>
|
<Component id="caseNameTextField" min="-2" pref="296" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/>
|
<Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/>
|
||||||
@ -51,7 +51,7 @@
|
|||||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
<Component id="caseNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
<Component id="caseNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
<Component id="caseNameTextField" alignment="3" min="-2" pref="20" max="-2" attributes="0"/>
|
<Component id="caseNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
|
||||||
</Group>
|
</Group>
|
||||||
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
<EmptySpace type="unrelated" max="-2" attributes="0"/>
|
||||||
<Group type="103" groupAlignment="3" attributes="0">
|
<Group type="103" groupAlignment="3" attributes="0">
|
||||||
|
@ -93,7 +93,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
|
|||||||
jLabel2 = new javax.swing.JLabel();
|
jLabel2 = new javax.swing.JLabel();
|
||||||
caseDirTextField = new javax.swing.JTextField();
|
caseDirTextField = new javax.swing.JTextField();
|
||||||
|
|
||||||
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14));
|
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N
|
||||||
|
|
||||||
org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N
|
org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N
|
||||||
@ -133,7 +133,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
|
|||||||
.addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||||
.addComponent(caseNameLabel)
|
.addComponent(caseNameLabel)
|
||||||
.addGap(26, 26, 26)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
|
||||||
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
@ -148,7 +148,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
|
|||||||
.addGap(18, 18, 18)
|
.addGap(18, 18, 18)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(caseNameLabel)
|
.addComponent(caseNameLabel)
|
||||||
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE))
|
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||||
.addComponent(caseDirLabel)
|
.addComponent(caseDirLabel)
|
||||||
|
12
Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java
Normal file → Executable file
12
Core/src/org/sleuthkit/autopsy/casemodule/services/Services.java
Normal file → Executable file
@ -2,7 +2,7 @@
|
|||||||
*
|
*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2012 Basis Technology Corp.
|
* Copyright 2012-2013 Basis Technology Corp.
|
||||||
*
|
*
|
||||||
* Copyright 2012 42six Solutions.
|
* Copyright 2012 42six Solutions.
|
||||||
* Contact: aebadirad <at> 42six <dot> com
|
* Contact: aebadirad <at> 42six <dot> com
|
||||||
@ -37,22 +37,30 @@ public class Services implements Closeable {
|
|||||||
|
|
||||||
// NOTE: all new services added to Services class must be added to this list
|
// NOTE: all new services added to Services class must be added to this list
|
||||||
// of services.
|
// of services.
|
||||||
private List<Closeable> services = new ArrayList<Closeable>();
|
private List<Closeable> services = new ArrayList<>();
|
||||||
|
|
||||||
// services
|
// services
|
||||||
private FileManager fileManager;
|
private FileManager fileManager;
|
||||||
|
private TagsManager tagsManager;
|
||||||
|
|
||||||
public Services(SleuthkitCase tskCase) {
|
public Services(SleuthkitCase tskCase) {
|
||||||
this.tskCase = tskCase;
|
this.tskCase = tskCase;
|
||||||
//create and initialize FileManager as early as possibly in the new/opened Case
|
//create and initialize FileManager as early as possibly in the new/opened Case
|
||||||
fileManager = new FileManager(tskCase);
|
fileManager = new FileManager(tskCase);
|
||||||
services.add(fileManager);
|
services.add(fileManager);
|
||||||
|
|
||||||
|
tagsManager = new TagsManager(tskCase);
|
||||||
|
services.add(tagsManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
public FileManager getFileManager() {
|
public FileManager getFileManager() {
|
||||||
return fileManager;
|
return fileManager;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TagsManager getTagsManager() {
|
||||||
|
return tagsManager;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void close() throws IOException {
|
public void close() throws IOException {
|
||||||
// close all services
|
// close all services
|
||||||
|
464
Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
Executable file
464
Core/src/org/sleuthkit/autopsy/casemodule/services/TagsManager.java
Executable file
@ -0,0 +1,464 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 Basis Technology Corp.
|
||||||
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
package org.sleuthkit.autopsy.casemodule.services;
|
||||||
|
|
||||||
|
import java.io.Closeable;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A per case instance of this class functions as an Autopsy service that
|
||||||
|
* manages the creation, updating, and deletion of tags applied to content and
|
||||||
|
* blackboard artifacts by users.
|
||||||
|
*/
|
||||||
|
public class TagsManager implements Closeable {
|
||||||
|
private static final String TAGS_SETTINGS_NAME = "Tags";
|
||||||
|
private static final String TAG_NAMES_SETTING_KEY = "TagNames";
|
||||||
|
private final SleuthkitCase tskCase;
|
||||||
|
private final HashMap<String, TagName> uniqueTagNames = new HashMap<>();
|
||||||
|
private boolean tagNamesInitialized = false; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
|
||||||
|
// Use this exception and the member hash map to manage uniqueness of hash
|
||||||
|
// names. This is deemed more proactive and informative than leaving this to
|
||||||
|
// the UNIQUE constraint on the display_name field of the tag_names table in
|
||||||
|
// the case database.
|
||||||
|
public class TagNameAlreadyExistsException extends Exception {
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Package-scope constructor for use of the Services class. An instance of
|
||||||
|
* TagsManager should be created for each case that is opened.
|
||||||
|
* @param [in] tskCase The SleuthkitCase object for the current case.
|
||||||
|
*/
|
||||||
|
TagsManager(SleuthkitCase tskCase) {
|
||||||
|
this.tskCase = tskCase;
|
||||||
|
// @@@ The removal of this call is a work around until database access on the EDT is correctly synchronized.
|
||||||
|
// getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all tag names currently available for tagging content or
|
||||||
|
* blackboard artifacts.
|
||||||
|
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<TagName> getAllTagNames() throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getAllTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets a list of all tag names currently used for tagging content or
|
||||||
|
* blackboard artifacts.
|
||||||
|
* @return A list, possibly empty, of TagName data transfer objects (DTOs).
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<TagName> getTagNamesInUse() throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getTagNamesInUse();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Checks whether a tag name with a given display name exists.
|
||||||
|
* @param [in] tagDisplayName The display name for which to check.
|
||||||
|
* @return True if the tag name exists, false otherwise.
|
||||||
|
*/
|
||||||
|
public synchronized boolean tagNameExists(String tagDisplayName) {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return uniqueTagNames.containsKey(tagDisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new tag name to the current case and to the tags settings.
|
||||||
|
* @param [in] displayName The display name for the new tag name.
|
||||||
|
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||||
|
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||||
|
*/
|
||||||
|
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
|
||||||
|
return addTagName(displayName, "", TagName.HTML_COLOR.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new tag name to the current case and to the tags settings.
|
||||||
|
* @param [in] displayName The display name for the new tag name.
|
||||||
|
* @param [in] description The description for the new tag name.
|
||||||
|
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||||
|
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||||
|
*/
|
||||||
|
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
|
||||||
|
return addTagName(displayName, description, TagName.HTML_COLOR.NONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Adds a new tag name to the current case and to the tags settings.
|
||||||
|
* @param [in] displayName The display name for the new tag name.
|
||||||
|
* @param [in] description The description for the new tag name.
|
||||||
|
* @param [in] color The HTML color to associate with the new tag name.
|
||||||
|
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||||
|
* @throws TagNameAlreadyExistsException, TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (uniqueTagNames.containsKey(displayName)) {
|
||||||
|
throw new TagNameAlreadyExistsException();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add the tag name to the case.
|
||||||
|
TagName newTagName = tskCase.addTagName(displayName, description, color);
|
||||||
|
|
||||||
|
// Add the tag name to the tags settings.
|
||||||
|
uniqueTagNames.put(newTagName.getDisplayName(), newTagName);
|
||||||
|
saveTagNamesToTagsSettings();
|
||||||
|
|
||||||
|
return newTagName;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags a content object.
|
||||||
|
* @param [in] content The content to tag.
|
||||||
|
* @param [in] tagName The name to use for the tag.
|
||||||
|
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public ContentTag addContentTag(Content content, TagName tagName) throws TskCoreException {
|
||||||
|
return addContentTag(content, tagName, "", -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags a content object.
|
||||||
|
* @param [in] content The content to tag.
|
||||||
|
* @param [in] tagName The name to use for the tag.
|
||||||
|
* @param [in] comment A comment to store with the tag.
|
||||||
|
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public ContentTag addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
|
||||||
|
return addContentTag(content, tagName, comment, -1, -1);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags a content object or a section of a content object.
|
||||||
|
* @param [in] content The content to tag.
|
||||||
|
* @param [in] tagName The name to use for the tag.
|
||||||
|
* @param [in] comment A comment to store with the tag.
|
||||||
|
* @param [in] beginByteOffset Designates the beginning of a tagged section.
|
||||||
|
* @param [in] endByteOffset Designates the end of a tagged section.
|
||||||
|
* @return A ContentTag data transfer object (DTO) representing the new tag.
|
||||||
|
* @throws IllegalArgumentException, TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized ContentTag addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (beginByteOffset >= 0 && endByteOffset >= 1) {
|
||||||
|
if (beginByteOffset > content.getSize() - 1) {
|
||||||
|
throw new IllegalArgumentException("beginByteOffset = " + beginByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endByteOffset > content.getSize() - 1) {
|
||||||
|
throw new IllegalArgumentException("endByteOffset = " + endByteOffset + " out of content size range (0 - " + (content.getSize() - 1) + ")");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (endByteOffset < beginByteOffset) {
|
||||||
|
throw new IllegalArgumentException("endByteOffset < beginByteOffset");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.addContentTag(content, tagName, comment, beginByteOffset, endByteOffset);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a content tag.
|
||||||
|
* @param [in] tag The tag to delete.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized void deleteContentTag(ContentTag tag) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
tskCase.deleteContentTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all content tags for the current case.
|
||||||
|
* @return A list, possibly empty, of content tags.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public List<ContentTag> getAllContentTags() throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getAllContentTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets content tags count by tag name.
|
||||||
|
* @param [in] tagName The tag name of interest.
|
||||||
|
* @return A count of the content tags with the specified tag name.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized long getContentTagsCountByTagName(TagName tagName) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getContentTagsCountByTagName(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets content tags by tag name.
|
||||||
|
* @param [in] tagName The tag name of interest.
|
||||||
|
* @return A list, possibly empty, of the content tags with the specified tag name.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<ContentTag> getContentTagsByTagName(TagName tagName) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getContentTagsByTagName(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets content tags count by content.
|
||||||
|
* @param [in] content The content of interest.
|
||||||
|
* @return A list, possibly empty, of the tags that have been applied to the artifact.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<ContentTag> getContentTagsByContent(Content content) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getContentTagsByContent(content);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags a blackboard artifact object.
|
||||||
|
* @param [in] artifact The blackboard artifact to tag.
|
||||||
|
* @param [in] tagName The name to use for the tag.
|
||||||
|
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
|
||||||
|
return addBlackboardArtifactTag(artifact, tagName, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tags a blackboard artifact object.
|
||||||
|
* @param [in] artifact The blackboard artifact to tag.
|
||||||
|
* @param [in] tagName The name to use for the tag.
|
||||||
|
* @param [in] comment A comment to store with the tag.
|
||||||
|
* @return A BlackboardArtifactTag data transfer object (DTO) representing the new tag.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized BlackboardArtifactTag addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.addBlackboardArtifactTag(artifact, tagName, comment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Deletes a blackboard artifact tag.
|
||||||
|
* @param [in] tag The tag to delete.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
tskCase.deleteBlackboardArtifactTag(tag);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets all blackboard artifact tags for the current case.
|
||||||
|
* @return A list, possibly empty, of blackboard artifact tags.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public List<BlackboardArtifactTag> getAllBlackboardArtifactTags() throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getAllBlackboardArtifactTags();
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets blackboard artifact tags count by tag name.
|
||||||
|
* @param [in] tagName The tag name of interest.
|
||||||
|
* @return A count of the blackboard artifact tags with the specified tag name.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized long getBlackboardArtifactTagsCountByTagName(TagName tagName) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getBlackboardArtifactTagsCountByTagName(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets blackboard artifact tags by tag name.
|
||||||
|
* @param [in] tagName The tag name of interest.
|
||||||
|
* @return A list, possibly empty, of the blackboard artifact tags with the specified tag name.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByTagName(TagName tagName) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getBlackboardArtifactTagsByTagName(tagName);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Gets blackboard artifact tags for a particular blackboard artifact.
|
||||||
|
* @param [in] artifact The blackboard artifact of interest.
|
||||||
|
* @return A list, possibly empty, of the tags that have been applied to the artifact.
|
||||||
|
* @throws TskCoreException
|
||||||
|
*/
|
||||||
|
public synchronized List<BlackboardArtifactTag> getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact) throws TskCoreException {
|
||||||
|
// @@@ This is a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
if (!tagNamesInitialized) {
|
||||||
|
getExistingTagNames();
|
||||||
|
}
|
||||||
|
|
||||||
|
return tskCase.getBlackboardArtifactTagsByArtifact(artifact);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void close() throws IOException {
|
||||||
|
saveTagNamesToTagsSettings();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getExistingTagNames() {
|
||||||
|
getTagNamesFromCurrentCase();
|
||||||
|
getTagNamesFromTagsSettings();
|
||||||
|
getPredefinedTagNames();
|
||||||
|
saveTagNamesToTagsSettings();
|
||||||
|
tagNamesInitialized = true; // @@@ This is part of a work around to be removed when database access on the EDT is correctly synchronized.
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getTagNamesFromCurrentCase() {
|
||||||
|
try {
|
||||||
|
List<TagName> currentTagNames = tskCase.getAllTagNames();
|
||||||
|
for (TagName tagName : currentTagNames) {
|
||||||
|
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag types from the current case", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getTagNamesFromTagsSettings() {
|
||||||
|
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY);
|
||||||
|
if (null != setting && !setting.isEmpty()) {
|
||||||
|
// Read the tag name setting and break it into tag name tuples.
|
||||||
|
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
|
||||||
|
|
||||||
|
// Parse each tuple and add the tag names to the current case, one
|
||||||
|
// at a time to gracefully discard any duplicates or corrupt tuples.
|
||||||
|
for (String tagNameTuple : tagNameTuples) {
|
||||||
|
String[] tagNameAttributes = tagNameTuple.split(",");
|
||||||
|
if (!uniqueTagNames.containsKey(tagNameAttributes[0])) {
|
||||||
|
try {
|
||||||
|
TagName tagName = tskCase.addTagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
|
||||||
|
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add saved tag name " + tagNameAttributes[0], ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void getPredefinedTagNames() {
|
||||||
|
if (!uniqueTagNames.containsKey("Bookmark")) {
|
||||||
|
try {
|
||||||
|
TagName tagName = tskCase.addTagName("Bookmark", "", TagName.HTML_COLOR.NONE);
|
||||||
|
uniqueTagNames.put(tagName.getDisplayName(), tagName);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to add predefined 'Bookmark' tag name", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void saveTagNamesToTagsSettings() {
|
||||||
|
if (!uniqueTagNames.isEmpty()) {
|
||||||
|
StringBuilder setting = new StringBuilder();
|
||||||
|
for (TagName tagName : uniqueTagNames.values()) {
|
||||||
|
if (setting.length() != 0) {
|
||||||
|
setting.append(";");
|
||||||
|
}
|
||||||
|
setting.append(tagName.getDisplayName()).append(",");
|
||||||
|
setting.append(tagName.getDescription()).append(",");
|
||||||
|
setting.append(tagName.getColor().name());
|
||||||
|
}
|
||||||
|
ModuleSettings.setConfigSetting(TAGS_SETTINGS_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -310,6 +310,11 @@
|
|||||||
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.ReportBodyFile.getDefault"/>
|
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.ReportBodyFile.getDefault"/>
|
||||||
<attr name="position" intvalue="902"/>
|
<attr name="position" intvalue="902"/>
|
||||||
</file>
|
</file>
|
||||||
|
<file name="org-sleuthkit-autopsy-report-FileReportText.instance">
|
||||||
|
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.FileReportModule"/>
|
||||||
|
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.FileReportText.getDefault"/>
|
||||||
|
<attr name="position" intvalue="903"/>
|
||||||
|
</file>
|
||||||
<!--<folder name="JavaHelp">
|
<!--<folder name="JavaHelp">
|
||||||
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
|
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
|
||||||
<attr name="position" intvalue="3075"/>
|
<attr name="position" intvalue="3075"/>
|
||||||
|
@ -257,20 +257,16 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
|||||||
outputViewPane.setText("");
|
outputViewPane.setText("");
|
||||||
prevPageButton.setEnabled(false);
|
prevPageButton.setEnabled(false);
|
||||||
nextPageButton.setEnabled(false);
|
nextPageButton.setEnabled(false);
|
||||||
|
currentNode = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setNode(Node selectedNode) {
|
public void setNode(Node selectedNode) {
|
||||||
// @@@ Remove this when the redundant setNode() calls problem is fixed.
|
|
||||||
if (currentNode == selectedNode) {
|
if (currentNode == selectedNode) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
currentNode = selectedNode;
|
currentNode = selectedNode;
|
||||||
|
|
||||||
// @@@ resetComponent() is currently a no-op due to the redundant setNode() calls problem.
|
|
||||||
// For now, do the reset here. Remove this when the redundant setNode() calls problem is fixed.
|
|
||||||
resetComponents();
|
|
||||||
|
|
||||||
// Make sure there is a node. Null might be passed to reset the viewer.
|
// Make sure there is a node. Null might be passed to reset the viewer.
|
||||||
if (selectedNode == null) {
|
if (selectedNode == null) {
|
||||||
return;
|
return;
|
||||||
@ -308,8 +304,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void resetComponent() {
|
public void resetComponent() {
|
||||||
// @@@ Restore this when the redundant setNode() calls problem is fixed.
|
resetComponents();
|
||||||
// resetComponents();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -185,6 +185,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
|||||||
@Override
|
@Override
|
||||||
public void resetComponent() {
|
public void resetComponent() {
|
||||||
videoPanel.reset();
|
videoPanel.reset();
|
||||||
|
imagePanel.reset();
|
||||||
lastFile = null;
|
lastFile = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -607,9 +607,11 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
* Set number of matches to be displayed in the top right
|
* Set number of matches to be displayed in the top right
|
||||||
* @param numMatches
|
* @param numMatches
|
||||||
*/
|
*/
|
||||||
public void setNumMatches(int numMatches) {
|
public void setNumMatches(Integer numMatches) {
|
||||||
|
if (this.numberMatchLabel != null) {
|
||||||
this.numberMatchLabel.setText(Integer.toString(numMatches));
|
this.numberMatchLabel.setText(Integer.toString(numMatches));
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private class DummyNodeListener implements NodeListener {
|
private class DummyNodeListener implements NodeListener {
|
||||||
private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait...";
|
private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait...";
|
||||||
@ -625,6 +627,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
if (load && containsReal(delta)) {
|
if (load && containsReal(delta)) {
|
||||||
load = false;
|
load = false;
|
||||||
setupTabs(nme.getNode());
|
setupTabs(nme.getNode());
|
||||||
|
updateMatches();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -637,8 +640,24 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Updates the Number of Matches label on the DataResultPanel.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
private void updateMatches() {
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (rootNode != null && rootNode.getChildren() != null) {
|
||||||
|
setNumMatches(rootNode.getChildren().getNodesCount());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void childrenRemoved(NodeMemberEvent nme) {
|
public void childrenRemoved(NodeMemberEvent nme) {
|
||||||
|
updateMatches();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -293,6 +293,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
|
|
||||||
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
||||||
|
|
||||||
|
if (ov == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
propertiesAcc.clear();
|
propertiesAcc.clear();
|
||||||
|
|
||||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||||
@ -339,7 +343,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
|||||||
//int scrollWidth = ttv.getWidth();
|
//int scrollWidth = ttv.getWidth();
|
||||||
int margin = 4;
|
int margin = 4;
|
||||||
int startColumn = 1;
|
int startColumn = 1;
|
||||||
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
|
|
||||||
|
// If there is only one column (which was removed from props above)
|
||||||
|
// Just let the table resize itself.
|
||||||
|
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
@ -404,6 +404,7 @@ public class FXVideoPanel extends MediaViewVideoPanel {
|
|||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
if (mediaPlayer != null) {
|
if (mediaPlayer != null) {
|
||||||
|
setInfoLabelText("");
|
||||||
if (mediaPlayer.getStatus() == Status.PLAYING) {
|
if (mediaPlayer.getStatus() == Status.PLAYING) {
|
||||||
mediaPlayer.stop();
|
mediaPlayer.stop();
|
||||||
}
|
}
|
||||||
|
@ -105,11 +105,7 @@ public class Installer extends ModuleInstall {
|
|||||||
}
|
}
|
||||||
|
|
||||||
final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI",
|
final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI",
|
||||||
"MenuUI",
|
};
|
||||||
"MenuItemUI",
|
|
||||||
"CheckBoxMenuItemUI",
|
|
||||||
"RadioButtonMenuItemUI",
|
|
||||||
"PopupMenuUI"};
|
|
||||||
|
|
||||||
Map<Object, Object> uiEntries = new TreeMap<Object, Object>();
|
Map<Object, Object> uiEntries = new TreeMap<Object, Object>();
|
||||||
|
|
||||||
|
@ -106,6 +106,15 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void reset() {
|
||||||
|
Platform.runLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
fxImageView.setImage(null);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show image
|
* Show image
|
||||||
*
|
*
|
||||||
|
@ -39,12 +39,6 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
|||||||
// 32 bit architectures
|
// 32 bit architectures
|
||||||
private static final String[] ARCH32 = new String[]{"x86"};
|
private static final String[] ARCH32 = new String[]{"x86"};
|
||||||
|
|
||||||
// A Gstreamer implementation of MediaViewVideoPanel
|
|
||||||
private static GstVideoPanel gstVideoPanel = null;
|
|
||||||
|
|
||||||
// A JavaFX implmentation of MediaViewVideoPanel
|
|
||||||
private static FXVideoPanel fxVideoPanel = null;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory Method to create a MediaViewVideoPanel.
|
* Factory Method to create a MediaViewVideoPanel.
|
||||||
*
|
*
|
||||||
@ -78,10 +72,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
|||||||
* @return a GstVideoPanel
|
* @return a GstVideoPanel
|
||||||
*/
|
*/
|
||||||
private static MediaViewVideoPanel getGstImpl() {
|
private static MediaViewVideoPanel getGstImpl() {
|
||||||
if (gstVideoPanel == null) {
|
return new GstVideoPanel();
|
||||||
gstVideoPanel = new GstVideoPanel();
|
|
||||||
}
|
|
||||||
return gstVideoPanel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -90,10 +81,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
|||||||
* @return a FXVideoPanel
|
* @return a FXVideoPanel
|
||||||
*/
|
*/
|
||||||
private static MediaViewVideoPanel getFXImpl() {
|
private static MediaViewVideoPanel getFXImpl() {
|
||||||
if (fxVideoPanel == null) {
|
return new FXVideoPanel();
|
||||||
fxVideoPanel = new FXVideoPanel();
|
|
||||||
}
|
|
||||||
return fxVideoPanel;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -42,6 +42,7 @@ public class ContextMenuExtensionPoint {
|
|||||||
if (!providerActions.isEmpty()) {
|
if (!providerActions.isEmpty()) {
|
||||||
actions.add(null); // Separator to set off this provider's actions.
|
actions.add(null); // Separator to set off this provider's actions.
|
||||||
actions.addAll(provider.getActions());
|
actions.addAll(provider.getActions());
|
||||||
|
actions.add(null); // Separator to set off this provider's actions.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return actions;
|
return actions;
|
||||||
|
@ -52,7 +52,8 @@ public class JLnkParser {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public JLNK parse() {
|
public JLNK parse() throws JLnkParserException {
|
||||||
|
try {
|
||||||
ByteBuffer bb = ByteBuffer.wrap(content);
|
ByteBuffer bb = ByteBuffer.wrap(content);
|
||||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||||
int header = bb.getInt();
|
int header = bb.getInt();
|
||||||
@ -210,7 +211,9 @@ public class JLnkParser {
|
|||||||
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
|
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
|
||||||
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
|
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
|
||||||
deviceName, deviceNameUnicode);
|
deviceName, deviceNameUnicode);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new JLnkParserException(e);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private String readStringData(ByteBuffer bb) {
|
private String readStringData(ByteBuffer bb) {
|
||||||
@ -337,3 +340,5 @@ public class JLnkParser {
|
|||||||
return new String(nameArr).split("\0")[0];
|
return new String(nameArr).split("\0")[0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
36
Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java
Executable file
36
Core/src/org/sleuthkit/autopsy/coreutils/JLnkParserException.java
Executable file
@ -0,0 +1,36 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2012 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.coreutils;
|
||||||
|
|
||||||
|
/**
|
||||||
|
*
|
||||||
|
* @author jwallace
|
||||||
|
*/
|
||||||
|
public class JLnkParserException extends Exception {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs an instance of
|
||||||
|
* <code>JLnkParserException</code> caused by the given exception.
|
||||||
|
*
|
||||||
|
* @param msg the detail message.
|
||||||
|
*/
|
||||||
|
public JLnkParserException(Exception cause) {
|
||||||
|
super(cause);
|
||||||
|
}
|
||||||
|
}
|
@ -146,6 +146,12 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
return "Known";
|
return "Known";
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
HASHSETS {
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "In Hashsets";
|
||||||
|
}
|
||||||
|
},
|
||||||
MD5HASH {
|
MD5HASH {
|
||||||
@Override
|
@Override
|
||||||
public String toString() {
|
public String toString() {
|
||||||
@ -188,6 +194,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
|
|||||||
map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
|
map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
|
||||||
map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
|
map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
|
||||||
map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
|
map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
|
||||||
|
map.put(AbstractFilePropertyType.HASHSETS.toString(), HashsetHits.getList(content.getSleuthkitCase(), content.getId()));
|
||||||
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
|
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children.Keys;
|
import org.openide.nodes.Children.Keys;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||||
import org.sleuthkit.datamodel.DerivedFile;
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
@ -157,8 +156,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractNode visit(Tags t) {
|
public AbstractNode visit(TagsNodeKey tagsNodeKey) {
|
||||||
return t.new TagsRootNode();
|
return new TagsNode();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode {
|
|||||||
return "artifact-icon.png";
|
return "artifact-icon.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -52,7 +52,7 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
|
|
||||||
T visit(EmailExtracted ee);
|
T visit(EmailExtracted ee);
|
||||||
|
|
||||||
T visit(Tags t);
|
T visit(TagsNodeKey tagsNodeKey);
|
||||||
|
|
||||||
T visit(DataSources i);
|
T visit(DataSources i);
|
||||||
|
|
||||||
@ -135,8 +135,8 @@ public interface AutopsyItemVisitor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(Tags t) {
|
public T visit(TagsNodeKey tagsNodeKey) {
|
||||||
return defaultVisit(t);
|
return defaultVisit(tagsNodeKey);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,6 +19,7 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -45,6 +46,15 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
|||||||
private Content associated;
|
private Content associated;
|
||||||
private List<NodeProperty> customProperties;
|
private List<NodeProperty> customProperties;
|
||||||
static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
|
||||||
|
/**
|
||||||
|
* Artifact types which should have the associated content's full unique path
|
||||||
|
* as a property.
|
||||||
|
*/
|
||||||
|
private static final Integer[] SHOW_UNIQUE_PATH = new Integer[] {
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
|
||||||
|
BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID(),
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Construct blackboard artifact node from an artifact and using provided
|
* Construct blackboard artifact node from an artifact and using provided
|
||||||
@ -107,30 +117,38 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
|||||||
entry.getValue()));
|
entry.getValue()));
|
||||||
}
|
}
|
||||||
|
|
||||||
String path = "";
|
|
||||||
try {
|
|
||||||
path = associated.getUniquePath();
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on " + associated);
|
|
||||||
}
|
|
||||||
final int artifactTypeID = artifact.getArtifactTypeID();
|
|
||||||
|
|
||||||
//custom additional properties
|
|
||||||
//TODO use addNodeProperty() instead of hardcoding here
|
|
||||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|
|
||||||
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
|
|
||||||
ss.put(new NodeProperty("File Path",
|
|
||||||
"File Path",
|
|
||||||
NO_DESCR,
|
|
||||||
path));
|
|
||||||
}
|
|
||||||
|
|
||||||
//append custom node properties
|
//append custom node properties
|
||||||
if (customProperties != null) {
|
if (customProperties != null) {
|
||||||
for (NodeProperty np : customProperties) {
|
for (NodeProperty np : customProperties) {
|
||||||
ss.put(np);
|
ss.put(np);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
final int artifactTypeId = artifact.getArtifactTypeID();
|
||||||
|
|
||||||
|
if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
|
||||||
|
String sourcePath = "";
|
||||||
|
try {
|
||||||
|
sourcePath = associated.getUniquePath();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to get unique path from: " + associated.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sourcePath.isEmpty() == false) {
|
||||||
|
ss.put(new NodeProperty("File Path", "File Path",
|
||||||
|
NO_DESCR, sourcePath));
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
String dataSource = "";
|
||||||
|
try {
|
||||||
|
dataSource = associated.getImage().getName();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to get image name from " + associated.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dataSource.isEmpty() == false) {
|
||||||
|
ss.put(new NodeProperty("Data Source", "Data Source",
|
||||||
|
NO_DESCR, dataSource));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return s;
|
return s;
|
||||||
@ -316,11 +334,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
|||||||
return "artifact-icon.png";
|
return "artifact-icon.png";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
94
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java
Executable file
94
Core/src/org/sleuthkit/autopsy/datamodel/BlackboardArtifactTagNode.java
Executable file
@ -0,0 +1,94 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteBlackboardArtifactTagAction;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class wrap BlackboardArtifactTag objects. In the Autopsy
|
||||||
|
* presentation of the SleuthKit data model, they are leaf nodes of a sub-tree
|
||||||
|
* organized as follows: there is a tags root node with tag name child nodes;
|
||||||
|
* tag name nodes have tag type child nodes; tag type nodes are the parents of
|
||||||
|
* either content or blackboard artifact tag nodes.
|
||||||
|
*/
|
||||||
|
public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/green-tag-icon-16.png";
|
||||||
|
private final BlackboardArtifactTag tag;
|
||||||
|
|
||||||
|
public BlackboardArtifactTagNode(BlackboardArtifactTag tag) {
|
||||||
|
super(Children.LEAF, Lookups.fixed(tag, tag.getArtifact(), tag.getContent()));
|
||||||
|
super.setName(tag.getContent().getName());
|
||||||
|
super.setDisplayName(tag.getContent().getName());
|
||||||
|
this.setIconBaseWithExtension(ICON_PATH);
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("Source File", "Source File", "", tag.getContent().getName()));
|
||||||
|
String contentPath;
|
||||||
|
try {
|
||||||
|
contentPath = tag.getContent().getUniquePath();
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
|
||||||
|
contentPath = "Unavailable";
|
||||||
|
}
|
||||||
|
properties.put(new NodeProperty("Source File Path", "Source File Path", "", contentPath));
|
||||||
|
properties.put(new NodeProperty("Result Type", "Result Type", "", tag.getArtifact().getDisplayName()));
|
||||||
|
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action[] getActions(boolean context) {
|
||||||
|
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), true);
|
||||||
|
actions.add(null); // Adds a menu item separator.
|
||||||
|
actions.add(DeleteBlackboardArtifactTagAction.getInstance());
|
||||||
|
return actions.toArray(new Action[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,303 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2012 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.datamodel;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.Action;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
|
||||||
import org.openide.nodes.Children;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.Lookup;
|
|
||||||
import org.openide.util.lookup.Lookups;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Support for bookmark (file and result/artifact) nodes and displaying
|
|
||||||
* bookmarks in the directory tree Bookmarks are divided into file and result
|
|
||||||
* children bookmarks.
|
|
||||||
*
|
|
||||||
* Bookmarks are specialized tags - TSK_TAG_NAME starts with File Bookmark or
|
|
||||||
* Result Bookmark
|
|
||||||
*
|
|
||||||
* @deprecated cosolidated under Tags
|
|
||||||
*
|
|
||||||
* TODO bookmark hierarchy support (TSK_TAG_NAME with slashes)
|
|
||||||
*/
|
|
||||||
@Deprecated
|
|
||||||
public class Bookmarks implements AutopsyVisitableItem {
|
|
||||||
|
|
||||||
public static final String NAME = "Bookmarks";
|
|
||||||
private static final String FILE_BOOKMARKS_LABEL_NAME = "File Bookmarks";
|
|
||||||
private static final String RESULT_BOOKMARKS_LABEL_NAME = "Result Bookmarks";
|
|
||||||
//bookmarks are specializations of tags
|
|
||||||
public static final String BOOKMARK_TAG_NAME = "Bookmark";
|
|
||||||
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
|
||||||
private static final Logger logger = Logger.getLogger(Bookmarks.class.getName());
|
|
||||||
private SleuthkitCase skCase;
|
|
||||||
private final Map<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>> data =
|
|
||||||
new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, List<BlackboardArtifact>>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
|
||||||
|
|
||||||
public Bookmarks(SleuthkitCase skCase) {
|
|
||||||
this.skCase = skCase;
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
|
||||||
return null; //v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bookmarks root node with file/result bookmarks
|
|
||||||
*/
|
|
||||||
public class BookmarksRootNode extends DisplayableItemNode {
|
|
||||||
|
|
||||||
public BookmarksRootNode() {
|
|
||||||
super(Children.create(new BookmarksRootChildren(), true), Lookups.singleton(NAME));
|
|
||||||
super.setName(NAME);
|
|
||||||
super.setDisplayName(NAME);
|
|
||||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
|
||||||
initData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initData() {
|
|
||||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, null);
|
|
||||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, null);
|
|
||||||
|
|
||||||
try {
|
|
||||||
|
|
||||||
//filter out tags that are not bookmarks
|
|
||||||
//we get bookmarks that have tag names that start with predefined names, preserving the bookmark hierarchy
|
|
||||||
List<BlackboardArtifact> tagFiles = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE,
|
|
||||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
|
|
||||||
BOOKMARK_TAG_NAME);
|
|
||||||
List<BlackboardArtifact> tagArtifacts = skCase.getBlackboardArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT,
|
|
||||||
BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME,
|
|
||||||
BOOKMARK_TAG_NAME);
|
|
||||||
|
|
||||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, tagFiles);
|
|
||||||
data.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, tagArtifacts);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Count not initialize bookmark nodes, ", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
|
||||||
return null; // v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet s = super.createSheet();
|
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
|
||||||
if (ss == null) {
|
|
||||||
ss = Sheet.createPropertiesSet();
|
|
||||||
s.put(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Name",
|
|
||||||
"Name",
|
|
||||||
"no description",
|
|
||||||
getName()));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bookmarks root child node creating types of bookmarks nodes
|
|
||||||
*/
|
|
||||||
private class BookmarksRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
|
|
||||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : data.keySet()) {
|
|
||||||
list.add(artType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
|
|
||||||
return new BookmarksNodeRoot(key, data.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Bookmarks node representation (file or result)
|
|
||||||
*/
|
|
||||||
public class BookmarksNodeRoot extends DisplayableItemNode {
|
|
||||||
|
|
||||||
public BookmarksNodeRoot(BlackboardArtifact.ARTIFACT_TYPE bookType, List<BlackboardArtifact> bookmarks) {
|
|
||||||
super(Children.create(new BookmarksChildrenNode(bookmarks), true), Lookups.singleton(bookType.getDisplayName()));
|
|
||||||
|
|
||||||
String name = null;
|
|
||||||
if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
|
||||||
name = FILE_BOOKMARKS_LABEL_NAME;
|
|
||||||
} else if (bookType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
|
||||||
name = RESULT_BOOKMARKS_LABEL_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.setName(name);
|
|
||||||
super.setDisplayName(name + " (" + bookmarks.size() + ")");
|
|
||||||
|
|
||||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet s = super.createSheet();
|
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
|
||||||
if (ss == null) {
|
|
||||||
ss = Sheet.createPropertiesSet();
|
|
||||||
s.put(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Name",
|
|
||||||
"Name",
|
|
||||||
"no description",
|
|
||||||
getName()));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
|
||||||
return null; //v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Node representing mail folder content (mail messages)
|
|
||||||
*/
|
|
||||||
private class BookmarksChildrenNode extends ChildFactory<BlackboardArtifact> {
|
|
||||||
|
|
||||||
private List<BlackboardArtifact> bookmarks;
|
|
||||||
|
|
||||||
private BookmarksChildrenNode(List<BlackboardArtifact> bookmarks) {
|
|
||||||
super();
|
|
||||||
this.bookmarks = bookmarks;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
|
||||||
list.addAll(bookmarks);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(BlackboardArtifact artifact) {
|
|
||||||
BlackboardArtifactNode bookmarkNode = null;
|
|
||||||
|
|
||||||
int artifactTypeID = artifact.getArtifactTypeID();
|
|
||||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
|
||||||
final BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
|
|
||||||
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH) {
|
|
||||||
@Override
|
|
||||||
public Action[] getActions(boolean bln) {
|
|
||||||
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
Action[] actions = new Action[1];
|
|
||||||
actions[0] = new AbstractAction("View Source Result") {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//open the source artifact in dir tree
|
|
||||||
if (sourceResult != null) {
|
|
||||||
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
|
|
||||||
v.viewArtifact(sourceResult);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
//add custom property
|
|
||||||
final String NO_DESCR = "no description";
|
|
||||||
String resultType = sourceResult.getDisplayName();
|
|
||||||
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
|
|
||||||
"Result Type",
|
|
||||||
NO_DESCR,
|
|
||||||
resultType);
|
|
||||||
bookmarkNode.addNodeProperty(resultTypeProp);
|
|
||||||
|
|
||||||
} else {
|
|
||||||
//file bookmark, no additional action
|
|
||||||
bookmarkNode = new BlackboardArtifactNode(artifact, BOOKMARK_ICON_PATH);
|
|
||||||
|
|
||||||
}
|
|
||||||
return bookmarkNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Links existing blackboard artifact (a tag) to this artifact. Linkage is
|
|
||||||
* made using TSK_TAGGED_ARTIFACT attribute.
|
|
||||||
*/
|
|
||||||
void addArtifactTag(BlackboardArtifact art, BlackboardArtifact tag) throws TskCoreException {
|
|
||||||
if (art.equals(tag)) {
|
|
||||||
throw new TskCoreException("Cannot tag the same artifact: id" + art.getArtifactID());
|
|
||||||
}
|
|
||||||
BlackboardAttribute attrLink = new BlackboardAttribute(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
|
|
||||||
"", art.getArtifactID());
|
|
||||||
tag.addAttribute(attrLink);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get tag artifacts linked to the artifact
|
|
||||||
*
|
|
||||||
* @param art artifact to get tags for
|
|
||||||
* @return list of children artifacts or an empty list
|
|
||||||
* @throws TskCoreException exception thrown if a critical error occurs
|
|
||||||
* within tsk core and child artifact could not be queried
|
|
||||||
*/
|
|
||||||
List<BlackboardArtifact> getTagArtifacts(BlackboardArtifact art) throws TskCoreException {
|
|
||||||
return skCase.getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, art.getArtifactID());
|
|
||||||
}
|
|
||||||
}
|
|
92
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java
Executable file
92
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagNode.java
Executable file
@ -0,0 +1,92 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteContentTagAction;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class wrap ContentTag objects. In the Autopsy
|
||||||
|
* presentation of the SleuthKit data model, they are leaf nodes of a tree
|
||||||
|
* consisting of content and blackboard artifact tags, grouped first by tag
|
||||||
|
* type, then by tag name.
|
||||||
|
*/
|
||||||
|
public class ContentTagNode extends DisplayableItemNode {
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/blue-tag-icon-16.png";
|
||||||
|
private final ContentTag tag;
|
||||||
|
|
||||||
|
public ContentTagNode(ContentTag tag) {
|
||||||
|
super(Children.LEAF, Lookups.fixed(tag, tag.getContent()));
|
||||||
|
super.setName(tag.getContent().getName());
|
||||||
|
super.setDisplayName(tag.getContent().getName());
|
||||||
|
this.setIconBaseWithExtension(ICON_PATH);
|
||||||
|
this.tag = tag;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("File", "File", "", tag.getContent().getName()));
|
||||||
|
String contentPath;
|
||||||
|
try {
|
||||||
|
contentPath = tag.getContent().getUniquePath();
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(ContentTagNode.class.getName()).log(Level.SEVERE, "Failed to get path for content (id = " + tag.getContent().getId() + ")", ex);
|
||||||
|
contentPath = "Unavailable";
|
||||||
|
}
|
||||||
|
properties.put(new NodeProperty("File Path", "File Path", "", contentPath));
|
||||||
|
properties.put(new NodeProperty("Comment", "Comment", "", tag.getComment()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Action[] getActions(boolean context) {
|
||||||
|
List<Action> actions = DataModelActionsFactory.getActions(tag.getContent(), false);
|
||||||
|
actions.add(null); // Adds a menu item separator.
|
||||||
|
actions.add(DeleteContentTagAction.getInstance());
|
||||||
|
return actions.toArray(new Action[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
108
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java
Executable file
108
Core/src/org/sleuthkit/autopsy/datamodel/ContentTagTypeNode.java
Executable file
@ -0,0 +1,108 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class are are elements of a directory tree sub-tree
|
||||||
|
* consisting of content and blackboard artifact tags, grouped first by tag type,
|
||||||
|
* then by tag name.
|
||||||
|
*/
|
||||||
|
public class ContentTagTypeNode extends DisplayableItemNode {
|
||||||
|
private static final String DISPLAY_NAME = "File Tags";
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||||
|
|
||||||
|
public ContentTagTypeNode(TagName tagName) {
|
||||||
|
super(Children.create(new ContentTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
|
||||||
|
|
||||||
|
long tagsCount = 0;
|
||||||
|
try {
|
||||||
|
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(ContentTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get content tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setName(DISPLAY_NAME);
|
||||||
|
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
|
||||||
|
this.setIconBaseWithExtension(ICON_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ContentTagNodeFactory extends ChildFactory<ContentTag> {
|
||||||
|
private final TagName tagName;
|
||||||
|
|
||||||
|
ContentTagNodeFactory(TagName tagName) {
|
||||||
|
this.tagName = tagName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<ContentTag> keys) {
|
||||||
|
// Use the content tags bearing the specified tag name as the keys.
|
||||||
|
try {
|
||||||
|
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName));
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(ContentTagTypeNode.ContentTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(ContentTag key) {
|
||||||
|
// The content tags to be wrapped are used as the keys.
|
||||||
|
return new ContentTagNode(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
182
Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java
Executable file
182
Core/src/org/sleuthkit/autopsy/datamodel/DataModelActionsFactory.java
Executable file
@ -0,0 +1,182 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
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.Content;
|
||||||
|
import org.sleuthkit.datamodel.DerivedFile;
|
||||||
|
import org.sleuthkit.datamodel.Directory;
|
||||||
|
import org.sleuthkit.datamodel.File;
|
||||||
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
|
import org.sleuthkit.datamodel.LocalFile;
|
||||||
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class provides methods for creating sets of actions for data model objects.
|
||||||
|
*/
|
||||||
|
// TODO: All of the methods below that deal with classes derived from AbstractFile are the same except for the creation of wrapper nodes to pass to actions.
|
||||||
|
// 1. Do the types of the wrapper nodes really need to vary? If not, it would mean a single
|
||||||
|
// static List<Action> getActions(AbstrctFile file, boolean isArtifactSource)
|
||||||
|
// method could be implemented. If the different nodes are necessary, is it merely because of some misuse of the Visitor pattern somewhere?
|
||||||
|
// 2. All of this would be much improved by not constructing nodes with actions, but this might be necessary with pushing of nodes rather than use of lookups to
|
||||||
|
// handle selections.
|
||||||
|
class DataModelActionsFactory {
|
||||||
|
static List<Action> getActions(File file, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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 with the same MD5 hash", fileNode));
|
||||||
|
actions.add(null); // creates a menu separator
|
||||||
|
actions.add(AddContentTagAction.getInstance());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(LayoutFile file, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(Directory directory, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(VirtualDirectory directory, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(LocalFile file, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(DerivedFile file, boolean isArtifactSource) {
|
||||||
|
List<Action> actions = new ArrayList<>();
|
||||||
|
actions.add(new ViewContextAction((isArtifactSource ? "View Source File in Directory" : "View File in Directory"), 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());
|
||||||
|
if (isArtifactSource) {
|
||||||
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
return actions;
|
||||||
|
}
|
||||||
|
|
||||||
|
static List<Action> getActions(Content content, boolean isArtifactSource) {
|
||||||
|
if (content instanceof File) {
|
||||||
|
return getActions((File)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else if (content instanceof LayoutFile) {
|
||||||
|
return getActions((LayoutFile)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else if (content instanceof Directory) {
|
||||||
|
return getActions((Directory)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else if (content instanceof VirtualDirectory) {
|
||||||
|
return getActions((VirtualDirectory)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else if (content instanceof LocalFile) {
|
||||||
|
return getActions((LocalFile)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else if (content instanceof DerivedFile) {
|
||||||
|
return getActions((DerivedFile)content, isArtifactSource);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return new ArrayList<>();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -39,8 +39,8 @@ public class DataSourcesNode extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.CONTENT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -109,8 +109,8 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.META;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -22,9 +22,9 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Directory;
|
import org.sleuthkit.datamodel.Directory;
|
||||||
@ -77,7 +77,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions.toArray(new Action[0]);
|
return actions.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
@ -93,7 +93,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.CONTENT;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 Basis Technology Corp.
|
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,12 +18,9 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.awt.datatransfer.Transferable;
|
|
||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.util.Lookup;
|
import org.openide.util.Lookup;
|
||||||
import org.openide.util.datatransfer.PasteType;
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface for all displayable Nodes
|
* Interface for all displayable Nodes
|
||||||
@ -38,34 +35,6 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
|||||||
super(children, lookup);
|
super(children, lookup);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract public boolean isLeafTypeNode();
|
||||||
/**
|
|
||||||
* Possible sub-implementations
|
|
||||||
*/
|
|
||||||
public enum TYPE {
|
|
||||||
CONTENT, ///< content node, such as file, image
|
|
||||||
ARTIFACT, ///< artifact data node
|
|
||||||
META, ///< top-level category node, such as view, filters, etc.
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get possible subtype of the displayable item node
|
|
||||||
* @return
|
|
||||||
*/
|
|
||||||
public abstract TYPE getDisplayableItemNodeType();
|
|
||||||
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Visitor pattern support.
|
|
||||||
*
|
|
||||||
* @param v visitor
|
|
||||||
* @return visitor's visit return value
|
|
||||||
*/
|
|
||||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 Basis Technology Corp.
|
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -30,12 +30,10 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
|
|||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visitor pattern for DisplayableItemNodes
|
* Visitor pattern implementation for DisplayableItemNodes
|
||||||
*/
|
*/
|
||||||
public interface DisplayableItemNodeVisitor<T> {
|
public interface DisplayableItemNodeVisitor<T> {
|
||||||
|
|
||||||
@ -85,11 +83,17 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
|
|
||||||
T visit(EmailExtractedFolderNode eefn);
|
T visit(EmailExtractedFolderNode eefn);
|
||||||
|
|
||||||
T visit(TagsRootNode bksrn);
|
T visit(TagsNode node);
|
||||||
|
|
||||||
T visit(TagsNodeRoot bksrn);
|
T visit(TagNameNode node);
|
||||||
|
|
||||||
T visit(TagNodeRoot tnr);
|
T visit(ContentTagTypeNode node);
|
||||||
|
|
||||||
|
T visit(ContentTagNode node);
|
||||||
|
|
||||||
|
T visit(BlackboardArtifactTagTypeNode node);
|
||||||
|
|
||||||
|
T visit(BlackboardArtifactTagNode node);
|
||||||
|
|
||||||
T visit(ViewsNode vn);
|
T visit(ViewsNode vn);
|
||||||
|
|
||||||
@ -265,18 +269,33 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(TagsRootNode bksrn) {
|
public T visit(TagsNode node) {
|
||||||
return defaultVisit(bksrn);
|
return defaultVisit(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(TagsNodeRoot bksnr) {
|
public T visit(TagNameNode node) {
|
||||||
return defaultVisit(bksnr);
|
return defaultVisit(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public T visit(TagNodeRoot tnr) {
|
public T visit(ContentTagTypeNode node) {
|
||||||
return defaultVisit(tnr);
|
return defaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(ContentTagNode node) {
|
||||||
|
return defaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(BlackboardArtifactTagTypeNode node) {
|
||||||
|
return defaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(BlackboardArtifactTagNode node) {
|
||||||
|
return defaultVisit(node);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -133,8 +133,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.ARTIFACT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -173,6 +173,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||||
//flatten all emails
|
//flatten all emails
|
||||||
|
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||||
for (String account : accounts.keySet()) {
|
for (String account : accounts.keySet()) {
|
||||||
Map<String, List<Long>> folders = accounts.get(account);
|
Map<String, List<Long>> folders = accounts.get(account);
|
||||||
for (String folder : folders.keySet()) {
|
for (String folder : folders.keySet()) {
|
||||||
@ -180,7 +181,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
for (long l : messages) {
|
for (long l : messages) {
|
||||||
try {
|
try {
|
||||||
//TODO: bulk artifact gettings
|
//TODO: bulk artifact gettings
|
||||||
list.add(skCase.getBlackboardArtifact(l));
|
tempList.add(skCase.getBlackboardArtifact(l));
|
||||||
} catch (TskException ex) {
|
} catch (TskException ex) {
|
||||||
logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
|
logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
|
||||||
}
|
}
|
||||||
@ -189,7 +190,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
list.addAll(tempList);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -214,8 +215,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.ARTIFACT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -271,11 +272,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
@ -293,6 +289,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -336,11 +337,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
@ -383,14 +379,16 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||||
|
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||||
for (long l : messages) {
|
for (long l : messages) {
|
||||||
try {
|
try {
|
||||||
//TODO: bulk artifact gettings
|
//TODO: bulk artifact gettings
|
||||||
list.add(skCase.getBlackboardArtifact(l));
|
tempList.add(skCase.getBlackboardArtifact(l));
|
||||||
} catch (TskException ex) {
|
} catch (TskException ex) {
|
||||||
logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
|
logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
list.addAll(tempList);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
|||||||
NAME));
|
NAME));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -22,11 +22,11 @@ import java.util.ArrayList;
|
|||||||
import java.util.List;
|
import java.util.List;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||||
@ -85,7 +85,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(TagAbstractFileAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
@ -170,13 +170,8 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.CONTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true; //false;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
@ -111,8 +111,8 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return DisplayableItemNode.TYPE.META;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
|
||||||
return DisplayableItemNode.TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode {
|
|||||||
getName()));
|
getName()));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -94,6 +94,43 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static public String getList(SleuthkitCase skCase, long objId) {
|
||||||
|
ResultSet rs = null;
|
||||||
|
String strList = "";
|
||||||
|
|
||||||
|
try {
|
||||||
|
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
|
||||||
|
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
|
||||||
|
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id "
|
||||||
|
+ "FROM blackboard_attributes,blackboard_artifacts WHERE "
|
||||||
|
+ "attribute_type_id=" + setNameId
|
||||||
|
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id"
|
||||||
|
+ " AND blackboard_artifacts.artifact_type_id=" + artId
|
||||||
|
+ " AND blackboard_artifacts.obj_id=" + objId;
|
||||||
|
rs = skCase.runQuery(query);
|
||||||
|
int i = 0;
|
||||||
|
while (rs.next()) {
|
||||||
|
if (i++ > 0) {
|
||||||
|
strList += ", ";
|
||||||
|
}
|
||||||
|
strList += rs.getString("value_text");
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
logger.log(Level.WARNING, "SQL Exception occurred: ", ex);
|
||||||
|
}
|
||||||
|
finally {
|
||||||
|
if (rs != null) {
|
||||||
|
try {
|
||||||
|
skCase.closeRunQuery(rs);
|
||||||
|
} catch (SQLException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return strList;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -113,8 +150,8 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.ARTIFACT;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode<Image> {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.CONTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Right click action for this node
|
* Right click action for this node
|
||||||
*
|
*
|
||||||
@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode<Image> {
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
|
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
|||||||
|
|
||||||
import java.sql.ResultSet;
|
import java.sql.ResultSet;
|
||||||
import java.sql.SQLException;
|
import java.sql.SQLException;
|
||||||
import java.sql.Statement;
|
import java.util.ArrayList;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.LinkedHashMap;
|
import java.util.LinkedHashMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
@ -28,16 +28,18 @@ import java.util.Map;
|
|||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.openide.nodes.AbstractNode;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
import org.openide.nodes.ChildFactory;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.Exceptions;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskException;
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Keyword hits node support
|
* Keyword hits node support
|
||||||
@ -170,13 +172,13 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public boolean isLeafTypeNode() {
|
||||||
return v.visit(this);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return TYPE.ARTIFACT;
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -229,11 +231,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
this.children = children;
|
this.children = children;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
@ -257,6 +254,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -310,11 +312,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
@ -327,11 +324,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
ss.put(new NodeProperty("List Name",
|
ss.put(new NodeProperty("List Name",
|
||||||
"List Name",
|
"List Name",
|
||||||
"no description",
|
"no description",
|
||||||
name));
|
getDisplayName()));
|
||||||
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Number of Hits",
|
ss.put(new NodeProperty("Files with Hits",
|
||||||
"Number of Hits",
|
"Files with Hits",
|
||||||
"no description",
|
"no description",
|
||||||
children.size()));
|
children.size()));
|
||||||
|
|
||||||
@ -350,20 +347,44 @@ public class KeywordHits implements AutopsyVisitableItem {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||||
|
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||||
for (long l : children) {
|
for (long l : children) {
|
||||||
try {
|
try {
|
||||||
//TODO: bulk artifact gettings
|
//TODO: bulk artifact gettings
|
||||||
list.add(skCase.getBlackboardArtifact(l));
|
tempList.add(skCase.getBlackboardArtifact(l));
|
||||||
} catch (TskException ex) {
|
} catch (TskException ex) {
|
||||||
logger.log(Level.WARNING, "TSK Exception occurred", ex);
|
logger.log(Level.WARNING, "TSK Exception occurred", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
list.addAll(tempList);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node createNodeForKey(BlackboardArtifact artifact) {
|
protected Node createNodeForKey(BlackboardArtifact artifact) {
|
||||||
return new BlackboardArtifactNode(artifact);
|
BlackboardArtifactNode n = new BlackboardArtifactNode(artifact);
|
||||||
|
AbstractFile file;
|
||||||
|
try {
|
||||||
|
file = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren");
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
n.addNodeProperty(new NodeProperty("ModifiedTime",
|
||||||
|
"Modified Time",
|
||||||
|
"Modified Time",
|
||||||
|
ContentUtils.getStringTime(file.getMtime(), file)));
|
||||||
|
n.addNodeProperty(new NodeProperty("AccessTime",
|
||||||
|
"Access Time",
|
||||||
|
"Access Time",
|
||||||
|
ContentUtils.getStringTime(file.getAtime(), file)));
|
||||||
|
n.addNodeProperty(new NodeProperty("ChangeTime",
|
||||||
|
"Change Time",
|
||||||
|
"Change Time",
|
||||||
|
ContentUtils.getStringTime(file.getCtime(), file)));
|
||||||
|
|
||||||
|
return n;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.datamodel.LayoutFile;
|
import org.sleuthkit.datamodel.LayoutFile;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -63,11 +63,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.CONTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
@ -96,6 +91,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -109,7 +109,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
|||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(TagAbstractFileAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
@ -26,12 +26,11 @@ import java.util.Map;
|
|||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
import org.sleuthkit.autopsy.directorytree.HashSearchAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -56,11 +55,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.CONTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Sheet createSheet() {
|
protected Sheet createSheet() {
|
||||||
Sheet s = super.createSheet();
|
Sheet s = super.createSheet();
|
||||||
@ -93,7 +87,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
|||||||
actionsList.add(ExtractAction.getInstance());
|
actionsList.add(ExtractAction.getInstance());
|
||||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||||
actionsList.add(null); // creates a menu separator
|
actionsList.add(null); // creates a menu separator
|
||||||
actionsList.add(TagAbstractFileAction.getInstance());
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actionsList.toArray(new Action[0]);
|
return actionsList.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
|
@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
|
|||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -42,8 +42,8 @@ public class RecentFilesNode extends DisplayableItemNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public boolean isLeafTypeNode() {
|
||||||
return TYPE.META;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -19,7 +19,6 @@
|
|||||||
package org.sleuthkit.autopsy.datamodel;
|
package org.sleuthkit.autopsy.datamodel;
|
||||||
|
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
import org.openide.nodes.AbstractNode;
|
|
||||||
import org.openide.nodes.Sheet;
|
import org.openide.nodes.Sheet;
|
||||||
import org.openide.util.lookup.Lookups;
|
import org.openide.util.lookup.Lookups;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
@ -36,13 +35,18 @@ public class ResultsNode extends DisplayableItemNode {
|
|||||||
new KeywordHits(sleuthkitCase),
|
new KeywordHits(sleuthkitCase),
|
||||||
new HashsetHits(sleuthkitCase),
|
new HashsetHits(sleuthkitCase),
|
||||||
new EmailExtracted(sleuthkitCase),
|
new EmailExtracted(sleuthkitCase),
|
||||||
new Tags(sleuthkitCase) //TODO move to the top of the tree
|
new TagsNodeKey()
|
||||||
)), Lookups.singleton(NAME));
|
)), Lookups.singleton(NAME));
|
||||||
setName(NAME);
|
setName(NAME);
|
||||||
setDisplayName(NAME);
|
setDisplayName(NAME);
|
||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -63,9 +67,4 @@ public class ResultsNode extends DisplayableItemNode {
|
|||||||
NAME));
|
NAME));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -80,16 +80,9 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
|||||||
if (o instanceof EmailExtracted)
|
if (o instanceof EmailExtracted)
|
||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//TODO check
|
|
||||||
case TSK_TAG_FILE:
|
case TSK_TAG_FILE:
|
||||||
if (o instanceof Tags)
|
|
||||||
this.refreshKey(o);
|
|
||||||
break;
|
|
||||||
|
|
||||||
//TODO check
|
|
||||||
case TSK_TAG_ARTIFACT:
|
case TSK_TAG_ARTIFACT:
|
||||||
if (o instanceof Tags)
|
if (o instanceof TagsNodeKey)
|
||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
@ -105,7 +98,7 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
|||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
else if (o instanceof EmailExtracted)
|
else if (o instanceof EmailExtracted)
|
||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
else if (o instanceof Tags)
|
else if (o instanceof TagsNodeKey)
|
||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
else if (o instanceof ExtractedContent)
|
else if (o instanceof ExtractedContent)
|
||||||
this.refreshKey(o);
|
this.refreshKey(o);
|
||||||
|
123
Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java
Executable file
123
Core/src/org/sleuthkit/autopsy/datamodel/TagNameNode.java
Executable file
@ -0,0 +1,123 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class are elements of Node hierarchies consisting of
|
||||||
|
* content and blackboard artifact tags, grouped first by tag type, then by
|
||||||
|
* tag name.
|
||||||
|
*/
|
||||||
|
public class TagNameNode extends DisplayableItemNode {
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||||
|
private static final String BOOKMARK_TAG_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
||||||
|
private final TagName tagName;
|
||||||
|
|
||||||
|
public TagNameNode(TagName tagName) {
|
||||||
|
super(Children.create(new TagTypeNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " Tags"));
|
||||||
|
this.tagName = tagName;
|
||||||
|
|
||||||
|
long tagsCount = 0;
|
||||||
|
try {
|
||||||
|
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getContentTagsCountByTagName(tagName);
|
||||||
|
tagsCount += Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "Failed to get tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setName(tagName.getDisplayName());
|
||||||
|
super.setDisplayName(tagName.getDisplayName() + " (" + tagsCount + ")");
|
||||||
|
if (tagName.getDisplayName().equals("Bookmark")) {
|
||||||
|
setIconBaseWithExtension(BOOKMARK_TAG_ICON_PATH);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
setIconBaseWithExtension(ICON_PATH);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("Name", "Name", tagName.getDescription(), getName()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
// See classes derived from DisplayableItemNodeVisitor<AbstractNode>
|
||||||
|
// for behavior added using the Visitor pattern.
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TagTypeNodeFactory extends ChildFactory<String> {
|
||||||
|
private static final String CONTENT_TAG_TYPE_NODE_KEY = "Content Tags";
|
||||||
|
private static final String BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY = "Result Tags";
|
||||||
|
private final TagName tagName;
|
||||||
|
|
||||||
|
TagTypeNodeFactory(TagName tagName) {
|
||||||
|
this.tagName = tagName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<String> keys) {
|
||||||
|
keys.add(CONTENT_TAG_TYPE_NODE_KEY);
|
||||||
|
keys.add(BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(String key) {
|
||||||
|
switch (key) {
|
||||||
|
case CONTENT_TAG_TYPE_NODE_KEY:
|
||||||
|
return new ContentTagTypeNode(tagName);
|
||||||
|
case BLACKBOARD_ARTIFACT_TAG_TYPE_NODE_KEY:
|
||||||
|
return new BlackboardArtifactTagTypeNode(tagName);
|
||||||
|
default:
|
||||||
|
Logger.getLogger(TagNameNode.class.getName()).log(Level.SEVERE, "{0} not a recognized key", key);
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,725 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2013 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.datamodel;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.sql.ResultSet;
|
|
||||||
import java.sql.SQLException;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.EnumMap;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import java.util.logging.Level;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.Action;
|
|
||||||
import org.openide.nodes.ChildFactory;
|
|
||||||
import org.openide.nodes.Children;
|
|
||||||
import org.openide.nodes.Node;
|
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.Lookup;
|
|
||||||
import org.openide.util.lookup.Lookups;
|
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.BlackboardResultViewer;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
|
||||||
import org.sleuthkit.autopsy.coreutils.ModuleSettings;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
|
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
* Support for tags in the directory tree. Tag nodes representing file and
|
|
||||||
* result tags, encapsulate TSK_TAG_FILE and TSK_TAG_ARTIFACT typed artifacts.
|
|
||||||
*
|
|
||||||
* The class implements querying of data model and populating node hierarchy
|
|
||||||
* using child factories.
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
public class Tags implements AutopsyVisitableItem {
|
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(Tags.class.getName());
|
|
||||||
private static final String FILE_TAG_LABEL_NAME = "File Tags";
|
|
||||||
private static final String RESULT_TAG_LABEL_NAME = "Result Tags";
|
|
||||||
private SleuthkitCase skCase;
|
|
||||||
public static final String NAME = "Tags";
|
|
||||||
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
|
||||||
//bookmarks are specializations of tags
|
|
||||||
public static final String BOOKMARK_TAG_NAME = "Bookmark";
|
|
||||||
private static final String BOOKMARK_ICON_PATH = "org/sleuthkit/autopsy/images/star-bookmark-icon-16.png";
|
|
||||||
private Map<BlackboardArtifact.ARTIFACT_TYPE, Map<String, List<BlackboardArtifact>>> tags;
|
|
||||||
private static final String EMPTY_COMMENT = "";
|
|
||||||
private static final String APP_SETTINGS_FILE_NAME = "app"; // @@@ TODO: Need a general app settings or user preferences file, this will do for now.
|
|
||||||
private static final String TAG_NAMES_SETTING_KEY = "tag_names";
|
|
||||||
private static final HashSet<String> appSettingTagNames = new HashSet<>();
|
|
||||||
private static final StringBuilder tagNamesAppSetting = new StringBuilder();
|
|
||||||
|
|
||||||
// When this class is loaded, either create an new app settings file or
|
|
||||||
// get the tag names setting from the existing app settings file.
|
|
||||||
static {
|
|
||||||
String setting = ModuleSettings.getConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY);
|
|
||||||
if (null != setting && !setting.isEmpty()) {
|
|
||||||
// Make a speedy lookup for the tag names in the setting to aid in the
|
|
||||||
// detection of new tag names.
|
|
||||||
List<String> tagNamesFromAppSettings = Arrays.asList(setting.split(","));
|
|
||||||
for (String tagName : tagNamesFromAppSettings) {
|
|
||||||
appSettingTagNames.add(tagName);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Load the raw comma separated values list from the setting into a
|
|
||||||
// string builder to facilitate adding new tag names to the list and writing
|
|
||||||
// it back to the app settings file.
|
|
||||||
tagNamesAppSetting.append(setting);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
Tags(SleuthkitCase skCase) {
|
|
||||||
this.skCase = skCase;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
|
||||||
return v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Root of all Tag nodes. This node is shown directly under Results in the
|
|
||||||
* directory tree.
|
|
||||||
*/
|
|
||||||
public class TagsRootNode extends DisplayableItemNode {
|
|
||||||
|
|
||||||
public TagsRootNode() {
|
|
||||||
super(Children.create(new Tags.TagsRootChildren(), true), Lookups.singleton(NAME));
|
|
||||||
super.setName(NAME);
|
|
||||||
super.setDisplayName(NAME);
|
|
||||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
|
||||||
initData();
|
|
||||||
}
|
|
||||||
|
|
||||||
private void initData() {
|
|
||||||
try {
|
|
||||||
// Get all file and artifact tags
|
|
||||||
|
|
||||||
//init data
|
|
||||||
tags = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
|
||||||
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE, new HashMap<String, List<BlackboardArtifact>>());
|
|
||||||
tags.put(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT, new HashMap<String, List<BlackboardArtifact>>());
|
|
||||||
|
|
||||||
//populate
|
|
||||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
|
|
||||||
final Map<String, List<BlackboardArtifact>> artTags = tags.get(artType);
|
|
||||||
for (BlackboardArtifact artifact : skCase.getBlackboardArtifacts(artType)) {
|
|
||||||
for (BlackboardAttribute attribute : artifact.getAttributes()) {
|
|
||||||
if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()) {
|
|
||||||
String tagName = attribute.getValueString();
|
|
||||||
if (artTags.containsKey(tagName)) {
|
|
||||||
List<BlackboardArtifact> artifacts = artTags.get(tagName);
|
|
||||||
artifacts.add(artifact);
|
|
||||||
} else {
|
|
||||||
List<BlackboardArtifact> artifacts = new ArrayList<>();
|
|
||||||
artifacts.add(artifact);
|
|
||||||
artTags.put(tagName, artifacts);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Count not initialize tag nodes", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
|
||||||
return v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet s = super.createSheet();
|
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
|
||||||
if (ss == null) {
|
|
||||||
ss = Sheet.createPropertiesSet();
|
|
||||||
s.put(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Name",
|
|
||||||
"Name",
|
|
||||||
"no description",
|
|
||||||
getName()));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
|
||||||
return DisplayableItemNode.TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* bookmarks root child node creating types of bookmarks nodes
|
|
||||||
*/
|
|
||||||
private class TagsRootChildren extends ChildFactory<BlackboardArtifact.ARTIFACT_TYPE> {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<BlackboardArtifact.ARTIFACT_TYPE> list) {
|
|
||||||
for (BlackboardArtifact.ARTIFACT_TYPE artType : tags.keySet()) {
|
|
||||||
list.add(artType);
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(BlackboardArtifact.ARTIFACT_TYPE key) {
|
|
||||||
return new TagsNodeRoot(key, tags.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Tag node representation (file or result)
|
|
||||||
*/
|
|
||||||
public class TagsNodeRoot extends DisplayableItemNode {
|
|
||||||
|
|
||||||
TagsNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
|
|
||||||
super(Children.create(new TagRootChildren(tagType, subTags), true), Lookups.singleton(tagType.getDisplayName()));
|
|
||||||
|
|
||||||
String name = null;
|
|
||||||
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
|
||||||
name = FILE_TAG_LABEL_NAME;
|
|
||||||
} else if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
|
||||||
name = RESULT_TAG_LABEL_NAME;
|
|
||||||
}
|
|
||||||
|
|
||||||
super.setName(name);
|
|
||||||
super.setDisplayName(name + " (" + subTags.values().size() + ")");
|
|
||||||
|
|
||||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet s = super.createSheet();
|
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
|
||||||
if (ss == null) {
|
|
||||||
ss = Sheet.createPropertiesSet();
|
|
||||||
s.put(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Name",
|
|
||||||
"Name",
|
|
||||||
"no description",
|
|
||||||
getName()));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
|
||||||
return v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Child factory to add all the Tag artifacts to a TagsRootNode with the tag
|
|
||||||
* name.
|
|
||||||
*/
|
|
||||||
private class TagRootChildren extends ChildFactory<String> {
|
|
||||||
|
|
||||||
private Map<String, List<BlackboardArtifact>> subTags;
|
|
||||||
private BlackboardArtifact.ARTIFACT_TYPE tagType;
|
|
||||||
|
|
||||||
TagRootChildren(BlackboardArtifact.ARTIFACT_TYPE tagType, Map<String, List<BlackboardArtifact>> subTags) {
|
|
||||||
super();
|
|
||||||
this.tagType = tagType;
|
|
||||||
this.subTags = subTags;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<String> list) {
|
|
||||||
list.addAll(subTags.keySet());
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(String key) {
|
|
||||||
return new Tags.TagNodeRoot(tagType, key, subTags.get(key));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Node for each unique tag name. Shown directly under Results > Tags.
|
|
||||||
*/
|
|
||||||
public class TagNodeRoot extends DisplayableItemNode {
|
|
||||||
|
|
||||||
TagNodeRoot(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
|
|
||||||
super(Children.create(new Tags.TagsChildrenNode(tagType, tagName, artifacts), true), Lookups.singleton(tagName));
|
|
||||||
|
|
||||||
super.setName(tagName);
|
|
||||||
super.setDisplayName(tagName + " (" + artifacts.size() + ")");
|
|
||||||
|
|
||||||
if (tagName.equals(BOOKMARK_TAG_NAME)) {
|
|
||||||
this.setIconBaseWithExtension(BOOKMARK_ICON_PATH);
|
|
||||||
} else {
|
|
||||||
this.setIconBaseWithExtension(TAG_ICON_PATH);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet s = super.createSheet();
|
|
||||||
Sheet.Set ss = s.get(Sheet.PROPERTIES);
|
|
||||||
if (ss == null) {
|
|
||||||
ss = Sheet.createPropertiesSet();
|
|
||||||
s.put(ss);
|
|
||||||
}
|
|
||||||
|
|
||||||
ss.put(new NodeProperty("Name",
|
|
||||||
"Name",
|
|
||||||
"no description",
|
|
||||||
getName()));
|
|
||||||
|
|
||||||
return s;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
|
||||||
return v.visit(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
|
||||||
return DisplayableItemNode.TYPE.ARTIFACT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean isLeafTypeNode() {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Node representing an individual Tag artifact. For each TagsNodeRoot under
|
|
||||||
* Results > Tags, this is one of the nodes listed in the result viewer.
|
|
||||||
*/
|
|
||||||
private class TagsChildrenNode extends ChildFactory<BlackboardArtifact> {
|
|
||||||
|
|
||||||
private List<BlackboardArtifact> artifacts;
|
|
||||||
private BlackboardArtifact.ARTIFACT_TYPE tagType;
|
|
||||||
private String tagName;
|
|
||||||
|
|
||||||
private TagsChildrenNode(BlackboardArtifact.ARTIFACT_TYPE tagType, String tagName, List<BlackboardArtifact> artifacts) {
|
|
||||||
super();
|
|
||||||
this.tagType = tagType;
|
|
||||||
this.tagName = tagName;
|
|
||||||
this.artifacts = artifacts;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
|
||||||
list.addAll(artifacts);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Node createNodeForKey(final BlackboardArtifact artifact) {
|
|
||||||
//create node with action
|
|
||||||
BlackboardArtifactNode tagNode = null;
|
|
||||||
|
|
||||||
String iconPath;
|
|
||||||
if (tagName.equals(BOOKMARK_TAG_NAME)) {
|
|
||||||
iconPath = BOOKMARK_ICON_PATH;
|
|
||||||
} else {
|
|
||||||
iconPath = TAG_ICON_PATH;
|
|
||||||
}
|
|
||||||
|
|
||||||
//create actions here where Tag logic belongs
|
|
||||||
//instead of DataResultFilterNode w/visitors, which is much less pluggable and cluttered
|
|
||||||
if (tagType.equals(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT)) {
|
|
||||||
//in case of result tag, add a action by sublcassing bb art node
|
|
||||||
//this action will be merged with other actions set DataResultFIlterNode
|
|
||||||
//otherwise in case of
|
|
||||||
tagNode = new BlackboardArtifactNode(artifact, iconPath) {
|
|
||||||
@Override
|
|
||||||
public Action[] getActions(boolean bln) {
|
|
||||||
//Action [] actions = super.getActions(bln); //To change body of generated methods, choose Tools | Templates.
|
|
||||||
Action[] actions = new Action[1];
|
|
||||||
actions[0] = new AbstractAction("View Source Result") {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
//open the source artifact in dir tree
|
|
||||||
BlackboardArtifact sourceArt = Tags.getArtifactFromTag(artifact.getArtifactID());
|
|
||||||
if (sourceArt != null) {
|
|
||||||
BlackboardResultViewer v = Lookup.getDefault().lookup(BlackboardResultViewer.class);
|
|
||||||
v.viewArtifact(sourceArt);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
return actions;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
//for file tag, don't subclass to add the additional actions
|
|
||||||
tagNode = new BlackboardArtifactNode(artifact, iconPath);
|
|
||||||
}
|
|
||||||
|
|
||||||
//add some additional node properties
|
|
||||||
int artifactTypeID = artifact.getArtifactTypeID();
|
|
||||||
final String NO_DESCR = "no description";
|
|
||||||
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
|
||||||
BlackboardArtifact sourceResult = Tags.getArtifactFromTag(artifact.getArtifactID());
|
|
||||||
String resultType = sourceResult.getDisplayName();
|
|
||||||
|
|
||||||
NodeProperty resultTypeProp = new NodeProperty("Source Result Type",
|
|
||||||
"Result Type",
|
|
||||||
NO_DESCR,
|
|
||||||
resultType);
|
|
||||||
|
|
||||||
|
|
||||||
tagNode.addNodeProperty(resultTypeProp);
|
|
||||||
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
//add source path property
|
|
||||||
final AbstractFile sourceFile = skCase.getAbstractFileById(artifact.getObjectID());
|
|
||||||
final String sourcePath = sourceFile.getUniquePath();
|
|
||||||
NodeProperty sourcePathProp = new NodeProperty("Source File Path",
|
|
||||||
"Source File Path",
|
|
||||||
NO_DESCR,
|
|
||||||
sourcePath);
|
|
||||||
|
|
||||||
|
|
||||||
tagNode.addNodeProperty(sourcePathProp);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Error getting a file from artifact to get source file path for a tag, ", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tagNode;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a tag for a file with TSK_TAG_NAME as tagName.
|
|
||||||
*
|
|
||||||
* @param file to create tag for
|
|
||||||
* @param tagName TSK_TAG_NAME
|
|
||||||
* @param comment the tag comment, or null if not present
|
|
||||||
*/
|
|
||||||
public static void createTag(AbstractFile file, String tagName, String comment) {
|
|
||||||
try {
|
|
||||||
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
|
||||||
List<BlackboardAttribute> attrs = new ArrayList<>();
|
|
||||||
|
|
||||||
|
|
||||||
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
|
|
||||||
"", tagName);
|
|
||||||
attrs.add(attr1);
|
|
||||||
|
|
||||||
if (comment != null && !comment.isEmpty()) {
|
|
||||||
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
|
|
||||||
"", comment);
|
|
||||||
attrs.add(attr2);
|
|
||||||
}
|
|
||||||
bookArt.addAttributes(attrs);
|
|
||||||
|
|
||||||
updateTagNamesAppSetting(tagName);
|
|
||||||
}
|
|
||||||
catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a tag for an artifact with TSK_TAG_NAME as tagName.
|
|
||||||
*
|
|
||||||
* @param artifact to create tag for
|
|
||||||
* @param tagName TSK_TAG_NAME
|
|
||||||
* @param comment the tag comment or null if not present
|
|
||||||
*/
|
|
||||||
public static void createTag(BlackboardArtifact artifact, String tagName, String comment) {
|
|
||||||
try {
|
|
||||||
Case currentCase = Case.getCurrentCase();
|
|
||||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
|
||||||
|
|
||||||
AbstractFile file = skCase.getAbstractFileById(artifact.getObjectID());
|
|
||||||
final BlackboardArtifact bookArt = file.newArtifact(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
|
||||||
List<BlackboardAttribute> attrs = new ArrayList<>();
|
|
||||||
|
|
||||||
|
|
||||||
BlackboardAttribute attr1 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID(),
|
|
||||||
"", tagName);
|
|
||||||
|
|
||||||
if (comment != null && !comment.isEmpty()) {
|
|
||||||
BlackboardAttribute attr2 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID(),
|
|
||||||
"", comment);
|
|
||||||
attrs.add(attr2);
|
|
||||||
}
|
|
||||||
|
|
||||||
BlackboardAttribute attr3 = new BlackboardAttribute(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID(),
|
|
||||||
"", artifact.getArtifactID());
|
|
||||||
attrs.add(attr1);
|
|
||||||
|
|
||||||
attrs.add(attr3);
|
|
||||||
bookArt.addAttributes(attrs);
|
|
||||||
|
|
||||||
updateTagNamesAppSetting(tagName);
|
|
||||||
}
|
|
||||||
catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to create tag for artifact " + artifact.getArtifactID(), ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static void updateTagNamesAppSetting(String tagName) {
|
|
||||||
// If this tag name is not in the current tag names app setting...
|
|
||||||
if (!appSettingTagNames.contains(tagName)) {
|
|
||||||
// Add it to the lookup.
|
|
||||||
appSettingTagNames.add(tagName);
|
|
||||||
|
|
||||||
// Add it to the setting and write the setting back to the app settings file.
|
|
||||||
if (tagNamesAppSetting.length() != 0) {
|
|
||||||
tagNamesAppSetting.append(",");
|
|
||||||
}
|
|
||||||
tagNamesAppSetting.append(tagName);
|
|
||||||
ModuleSettings.setConfigSetting(APP_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY, tagNamesAppSetting.toString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a bookmark tag for a file.
|
|
||||||
*
|
|
||||||
* @param file to create bookmark tag for
|
|
||||||
* @param comment the bookmark comment
|
|
||||||
*/
|
|
||||||
public static void createBookmark(AbstractFile file, String comment) {
|
|
||||||
createTag(file, Tags.BOOKMARK_TAG_NAME, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Create a bookmark tag for an artifact.
|
|
||||||
*
|
|
||||||
* @param artifact to create bookmark tag for
|
|
||||||
* @param comment the bookmark comment
|
|
||||||
*/
|
|
||||||
public static void createBookmark(BlackboardArtifact artifact, String comment) {
|
|
||||||
createTag(artifact, Tags.BOOKMARK_TAG_NAME, comment);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of all the bookmarks.
|
|
||||||
*
|
|
||||||
* @return a list of all bookmark artifacts
|
|
||||||
*/
|
|
||||||
static List<BlackboardArtifact> getBookmarks() {
|
|
||||||
try {
|
|
||||||
Case currentCase = Case.getCurrentCase();
|
|
||||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
|
||||||
return skCase.getBlackboardArtifacts(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME, Tags.BOOKMARK_TAG_NAME);
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to get list of artifacts from the case", ex);
|
|
||||||
}
|
|
||||||
return new ArrayList<>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of all the unique tag names associated with the current case plus any
|
|
||||||
* tag names stored in the application settings file.
|
|
||||||
*
|
|
||||||
* @return A collection of tag names.
|
|
||||||
*/
|
|
||||||
public static TreeSet<String> getAllTagNames() {
|
|
||||||
// Use a TreeSet<> so the union of the tag names from the two sources will be sorted.
|
|
||||||
TreeSet<String> tagNames = getTagNamesFromCurrentCase();
|
|
||||||
tagNames.addAll(appSettingTagNames);
|
|
||||||
|
|
||||||
// Make sure the book mark tag is always included.
|
|
||||||
tagNames.add(BOOKMARK_TAG_NAME);
|
|
||||||
|
|
||||||
return tagNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get a list of all the unique tag names associated with the current case.
|
|
||||||
* Uses a custom query for speed when dealing with thousands of tags.
|
|
||||||
*
|
|
||||||
* @return A collection of tag names.
|
|
||||||
*/
|
|
||||||
@SuppressWarnings("deprecation")
|
|
||||||
public static TreeSet<String> getTagNamesFromCurrentCase() {
|
|
||||||
TreeSet<String> tagNames = new TreeSet<>();
|
|
||||||
|
|
||||||
ResultSet rs = null;
|
|
||||||
SleuthkitCase skCase = null;
|
|
||||||
try {
|
|
||||||
skCase = Case.getCurrentCase().getSleuthkitCase();
|
|
||||||
rs = skCase.runQuery("SELECT value_text"
|
|
||||||
+ " FROM blackboard_attributes"
|
|
||||||
+ " WHERE attribute_type_id = " + BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID()
|
|
||||||
+ " GROUP BY value_text"
|
|
||||||
+ " ORDER BY value_text");
|
|
||||||
while (rs.next()) {
|
|
||||||
tagNames.add(rs.getString("value_text"));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (IllegalStateException ex) {
|
|
||||||
// Case.getCurrentCase() throws IllegalStateException if there is no current autopsy case.
|
|
||||||
}
|
|
||||||
catch (SQLException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to query the blackboard for tag names", ex);
|
|
||||||
}
|
|
||||||
finally {
|
|
||||||
if (null != skCase && null != rs) {
|
|
||||||
try {
|
|
||||||
skCase.closeRunQuery(rs);
|
|
||||||
} catch (SQLException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to close the query for blackboard for tag names", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Make sure the book mark tag is always included.
|
|
||||||
tagNames.add(BOOKMARK_TAG_NAME);
|
|
||||||
|
|
||||||
return tagNames;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the tag comment for a specified tag.
|
|
||||||
*
|
|
||||||
* @param tagArtifactId artifact id of the tag
|
|
||||||
* @return the tag comment
|
|
||||||
*/
|
|
||||||
static String getCommentFromTag(long tagArtifactId) {
|
|
||||||
try {
|
|
||||||
Case currentCase = Case.getCurrentCase();
|
|
||||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
|
||||||
|
|
||||||
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
|
|
||||||
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
|
||||||
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
|
||||||
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_COMMENT.getTypeID()) {
|
|
||||||
return att.getValueString();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case", ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return EMPTY_COMMENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get the artifact for a result tag.
|
|
||||||
*
|
|
||||||
* @param tagArtifactId artifact id of the tag
|
|
||||||
* @return the tag's artifact
|
|
||||||
*/
|
|
||||||
static BlackboardArtifact getArtifactFromTag(long tagArtifactId) {
|
|
||||||
try {
|
|
||||||
Case currentCase = Case.getCurrentCase();
|
|
||||||
SleuthkitCase skCase = currentCase.getSleuthkitCase();
|
|
||||||
|
|
||||||
BlackboardArtifact artifact = skCase.getBlackboardArtifact(tagArtifactId);
|
|
||||||
if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
|
||||||
|| artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
|
||||||
List<BlackboardAttribute> attributes = artifact.getAttributes();
|
|
||||||
for (BlackboardAttribute att : attributes) {
|
|
||||||
if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()) {
|
|
||||||
return skCase.getBlackboardArtifact(att.getValueLong());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to get artifact " + tagArtifactId + " from case.");
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
|
|
||||||
*
|
|
||||||
* @param artifact The artifact
|
|
||||||
* @return A set of unique tag names
|
|
||||||
*/
|
|
||||||
public static HashSet<String> getUniqueTagNamesForArtifact(BlackboardArtifact artifact) {
|
|
||||||
return getUniqueTagNamesForArtifact(artifact.getArtifactID(), artifact.getArtifactTypeID());
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Looks up the tag names associated with either a tagged artifact or a tag artifact.
|
|
||||||
*
|
|
||||||
* @param artifactID The ID of the artifact
|
|
||||||
* @param artifactTypeID The ID of the artifact type
|
|
||||||
* @return A set of unique tag names
|
|
||||||
*/
|
|
||||||
public static HashSet<String> getUniqueTagNamesForArtifact(long artifactID, int artifactTypeID) {
|
|
||||||
HashSet<String> tagNames = new HashSet<>();
|
|
||||||
|
|
||||||
try {
|
|
||||||
ArrayList<Long> tagArtifactIDs = new ArrayList<>();
|
|
||||||
if (artifactTypeID == ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() ||
|
|
||||||
artifactTypeID == ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
|
||||||
tagArtifactIDs.add(artifactID);
|
|
||||||
} else {
|
|
||||||
List<BlackboardArtifact> tags = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifacts(ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT, artifactID);
|
|
||||||
for (BlackboardArtifact tag : tags) {
|
|
||||||
tagArtifactIDs.add(tag.getArtifactID());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (Long tagArtifactID : tagArtifactIDs) {
|
|
||||||
String whereClause = "WHERE artifact_id = " + tagArtifactID + " AND attribute_type_id = " + ATTRIBUTE_TYPE.TSK_TAG_NAME.getTypeID();
|
|
||||||
List<BlackboardAttribute> attributes = Case.getCurrentCase().getSleuthkitCase().getMatchingAttributes(whereClause);
|
|
||||||
for (BlackboardAttribute attr : attributes) {
|
|
||||||
tagNames.add(attr.getValueString());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifactID, ex);
|
|
||||||
}
|
|
||||||
|
|
||||||
return tagNames;
|
|
||||||
}
|
|
||||||
}
|
|
91
Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java
Executable file
91
Core/src/org/sleuthkit/autopsy/datamodel/TagsNode.java
Executable file
@ -0,0 +1,91 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class are the root nodes of tree that is a sub-tree of the
|
||||||
|
* Autopsy presentation of the SleuthKit data model. The sub-tree consists of
|
||||||
|
* content and blackboard artifact tags, grouped first by tag type, then by
|
||||||
|
* tag name.
|
||||||
|
*/
|
||||||
|
public class TagsNode extends DisplayableItemNode {
|
||||||
|
private static final String DISPLAY_NAME = "Tags";
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||||
|
|
||||||
|
public TagsNode() {
|
||||||
|
super(Children.create(new TagNameNodeFactory(), true), Lookups.singleton(DISPLAY_NAME));
|
||||||
|
super.setName(DISPLAY_NAME);
|
||||||
|
super.setDisplayName(DISPLAY_NAME);
|
||||||
|
this.setIconBaseWithExtension(ICON_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class TagNameNodeFactory extends ChildFactory<TagName> {
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<TagName> keys) {
|
||||||
|
try {
|
||||||
|
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getTagNamesInUse());
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(TagNameNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(TagName key) {
|
||||||
|
return new TagNameNode(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
34
Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java
Executable file
34
Core/src/org/sleuthkit/autopsy/datamodel/TagsNodeKey.java
Executable file
@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.datamodel;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class act as keys for use by instances of the
|
||||||
|
* RootContentChildren class. RootContentChildren is a NetBeans child node
|
||||||
|
* factory built on top of the NetBeans Children.Keys class.
|
||||||
|
*/
|
||||||
|
public class TagsNodeKey implements AutopsyVisitableItem {
|
||||||
|
// Creation of a TagsNode object corresponding to a TagsNodeKey object is done
|
||||||
|
// by a CreateAutopsyNodeVisitor dispatched from the AbstractContentChildren
|
||||||
|
// override of Children.Keys<T>.createNodes().
|
||||||
|
@Override
|
||||||
|
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
}
|
@ -45,6 +45,11 @@ public class ViewsNode extends DisplayableItemNode {
|
|||||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png");
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
|
|||||||
NAME));
|
NAME));
|
||||||
return s;
|
return s;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.META;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
|||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
|
||||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
@ -82,7 +81,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
|||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions.toArray(new Action[0]);
|
return actions.toArray(new Action[0]);
|
||||||
}
|
}
|
||||||
@ -120,11 +118,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
|||||||
return v.visit(this);
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public TYPE getDisplayableItemNodeType() {
|
|
||||||
return TYPE.CONTENT;
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean isLeafTypeNode() {
|
public boolean isLeafTypeNode() {
|
||||||
return true;
|
return true;
|
||||||
|
@ -101,12 +101,12 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
public boolean isLeafTypeNode() {
|
||||||
return v.visit(this);
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public TYPE getDisplayableItemNodeType() {
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
return TYPE.CONTENT;
|
return v.visit(this);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
113
Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java
Executable file
113
Core/src/org/sleuthkit/autopsy/directorytree/BlackboardArtifactTagTypeNode.java
Executable file
@ -0,0 +1,113 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.directorytree;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import org.openide.nodes.ChildFactory;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Node;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactTagNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.DisplayableItemNodeVisitor;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.NodeProperty;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||||
|
import org.sleuthkit.datamodel.TagName;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Instances of this class are elements in a sub-tree of the Autopsy
|
||||||
|
* presentation of the SleuthKit data model. The sub-tree consists of content
|
||||||
|
* and blackboard artifact tags, grouped first by tag type, then by tag name.
|
||||||
|
*/
|
||||||
|
public class BlackboardArtifactTagTypeNode extends DisplayableItemNode {
|
||||||
|
private static final String DISPLAY_NAME = "Result Tags";
|
||||||
|
private static final String ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
|
||||||
|
|
||||||
|
public BlackboardArtifactTagTypeNode(TagName tagName) {
|
||||||
|
super(Children.create(new BlackboardArtifactTagNodeFactory(tagName), true), Lookups.singleton(tagName.getDisplayName() + " " + DISPLAY_NAME));
|
||||||
|
|
||||||
|
long tagsCount = 0;
|
||||||
|
try {
|
||||||
|
tagsCount = Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsCountByTagName(tagName);
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(BlackboardArtifactTagTypeNode.class.getName()).log(Level.SEVERE, "Failed to get blackboard artifact tags count for " + tagName.getDisplayName() + " tag name", ex);
|
||||||
|
}
|
||||||
|
|
||||||
|
super.setName(DISPLAY_NAME);
|
||||||
|
super.setDisplayName(DISPLAY_NAME + " (" + tagsCount + ")");
|
||||||
|
this.setIconBaseWithExtension(ICON_PATH);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
Sheet propertySheet = super.createSheet();
|
||||||
|
Sheet.Set properties = propertySheet.get(Sheet.PROPERTIES);
|
||||||
|
if (properties == null) {
|
||||||
|
properties = Sheet.createPropertiesSet();
|
||||||
|
propertySheet.put(properties);
|
||||||
|
}
|
||||||
|
|
||||||
|
properties.put(new NodeProperty("Name", "Name", "", getName()));
|
||||||
|
|
||||||
|
return propertySheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||||
|
return v.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class BlackboardArtifactTagNodeFactory extends ChildFactory<BlackboardArtifactTag> {
|
||||||
|
private final TagName tagName;
|
||||||
|
|
||||||
|
BlackboardArtifactTagNodeFactory(TagName tagName) {
|
||||||
|
this.tagName = tagName;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
||||||
|
try {
|
||||||
|
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
||||||
|
keys.addAll(Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName));
|
||||||
|
}
|
||||||
|
catch (TskCoreException ex) {
|
||||||
|
Logger.getLogger(BlackboardArtifactTagTypeNode.BlackboardArtifactTagNodeFactory.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Node createNodeForKey(BlackboardArtifactTag key) {
|
||||||
|
// The blackboard artifact tags to be wrapped are used as the keys.
|
||||||
|
return new BlackboardArtifactTagNode(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -47,17 +47,3 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size:
|
|||||||
ImageDetailsPanel.imgSectorSizeValue.text=...
|
ImageDetailsPanel.imgSectorSizeValue.text=...
|
||||||
DirectoryTreeTopComponent.backButton.text=
|
DirectoryTreeTopComponent.backButton.text=
|
||||||
DirectoryTreeTopComponent.forwardButton.text=
|
DirectoryTreeTopComponent.forwardButton.text=
|
||||||
CreateTagDialog.cancelButton.text=Cancel
|
|
||||||
CreateTagDialog.okButton.text=OK
|
|
||||||
CreateTagDialog.tagNameField.text=
|
|
||||||
CreateTagDialog.tagNameLabel.text=Tag Name:
|
|
||||||
CreateTagDialog.preexistingLabel.text=Pre-existing Tags:
|
|
||||||
CreateTagDialog.newTagPanel.border.title=New Tag
|
|
||||||
TagAndCommentDialog.tagLabel.text=Tag:
|
|
||||||
TagAndCommentDialog.tagCombo.toolTipText=Select tag to use
|
|
||||||
TagAndCommentDialog.cancelButton.text=Cancel
|
|
||||||
TagAndCommentDialog.okButton.text=OK
|
|
||||||
TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
|
|
||||||
TagAndCommentDialog.commentText.text=
|
|
||||||
TagAndCommentDialog.commentLabel.text=Comment:
|
|
||||||
TagAndCommentDialog.newTagButton.text=New Tag
|
|
||||||
|
@ -18,6 +18,8 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.directorytree;
|
package org.sleuthkit.autopsy.directorytree;
|
||||||
|
|
||||||
|
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.beans.PropertyVetoException;
|
import java.beans.PropertyVetoException;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
@ -38,6 +40,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp
|
|||||||
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
|
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
|
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
|
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||||
@ -62,8 +65,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
|
|||||||
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
|
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
|
import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
|
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
import org.sleuthkit.autopsy.datamodel.TagNameNode;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
@ -169,6 +171,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
//set up actions for artifact node based on its Content object
|
//set up actions for artifact node based on its Content object
|
||||||
//TODO all actions need to be consolidated in single place!
|
//TODO all actions need to be consolidated in single place!
|
||||||
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
|
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
|
||||||
|
// TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals
|
||||||
|
// can be removed.
|
||||||
|
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
|
|
||||||
@ -207,8 +211,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -224,8 +228,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -241,8 +245,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
}
|
}
|
||||||
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
|
||||||
@ -257,8 +261,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
}
|
}
|
||||||
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
|
||||||
@ -274,8 +278,8 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||||
actions.add(null); // creates a menu separator
|
actions.add(null); // creates a menu separator
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -410,13 +414,18 @@ public class DataResultFilterNode extends FilterNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractAction visit(TagNodeRoot tnr) {
|
public AbstractAction visit(TagNameNode node) {
|
||||||
return openChild(tnr);
|
return openChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public AbstractAction visit(TagsNodeRoot tnr) {
|
public AbstractAction visit(ContentTagTypeNode node) {
|
||||||
return openChild(tnr);
|
return openChild(node);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public AbstractAction visit(BlackboardArtifactTagTypeNode node) {
|
||||||
|
return openChild(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
|
|||||||
import java.beans.PropertyChangeListener;
|
import java.beans.PropertyChangeListener;
|
||||||
import java.beans.PropertyChangeSupport;
|
import java.beans.PropertyChangeSupport;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.LinkedList;
|
import java.util.LinkedList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
@ -804,7 +805,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
* Refreshes the nodes in the tree to reflect updates in the database should
|
* Refreshes the nodes in the tree to reflect updates in the database should
|
||||||
* be called in the gui thread
|
* be called in the gui thread
|
||||||
*/
|
*/
|
||||||
void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
||||||
//save current selection
|
//save current selection
|
||||||
Node selectedNode = getSelectedNode();
|
Node selectedNode = getSelectedNode();
|
||||||
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
|
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
|
||||||
@ -856,38 +857,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set selected node using the previously saved selection path to the
|
* Set the selected node using a path to a previously selected node.
|
||||||
* selected node
|
|
||||||
*
|
*
|
||||||
* @param path node path with node names
|
* @param previouslySelectedNodePath Path to a previously selected node.
|
||||||
* @param rootNodeName name of the root node to match or null if any
|
* @param rootNodeName Name of the root node to match, may be null.
|
||||||
*/
|
*/
|
||||||
private void setSelectedNode(final String[] path, final String rootNodeName) {
|
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
||||||
if (path == null) {
|
if (previouslySelectedNodePath == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
SwingUtilities.invokeLater(new Runnable() {
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
@Override
|
@Override
|
||||||
public void run() {
|
public void run() {
|
||||||
|
if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
|
||||||
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) {
|
Node selectedNode = null;
|
||||||
|
ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
|
||||||
|
while (null == selectedNode && !selectedNodePath.isEmpty()) {
|
||||||
try {
|
try {
|
||||||
Node newSelection = NodeOp.findPath(em.getRootContext(), path);
|
selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
|
||||||
|
}
|
||||||
|
catch (NodeNotFoundException ex) {
|
||||||
|
// The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
|
||||||
|
if (selectedNodePath.size() > 1) {
|
||||||
|
selectedNodePath.remove(selectedNodePath.size() - 1);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
StringBuilder nodePath = new StringBuilder();
|
||||||
|
for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
|
||||||
|
nodePath.append(previouslySelectedNodePath[i]).append("/");
|
||||||
|
}
|
||||||
|
logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (newSelection != null) {
|
if (null != selectedNode) {
|
||||||
if (rootNodeName != null) {
|
if (rootNodeName != null) {
|
||||||
//called from tree auto refresh context
|
//called from tree auto refresh context
|
||||||
//remove last from backlist, because auto select will result in duplication
|
//remove last from backlist, because auto select will result in duplication
|
||||||
backList.pollLast();
|
backList.pollLast();
|
||||||
}
|
}
|
||||||
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection});
|
try {
|
||||||
|
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
|
||||||
|
}
|
||||||
|
catch (PropertyVetoException ex) {
|
||||||
|
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
// We need to set the selection, which will refresh dataresult and get rid of the oob exception
|
|
||||||
} catch (NodeNotFoundException ex) {
|
|
||||||
logger.log(Level.WARNING, "Node not found", ex);
|
|
||||||
} catch (PropertyVetoException ex) {
|
|
||||||
logger.log(Level.WARNING, "Property Veto", ex);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 Basis Technology Corp.
|
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.directorytree;
|
package org.sleuthkit.autopsy.directorytree;
|
||||||
|
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
import java.awt.Toolkit;
|
import java.awt.Toolkit;
|
||||||
import java.awt.Dimension;
|
import java.awt.Dimension;
|
||||||
import java.awt.Font;
|
import java.awt.Font;
|
||||||
@ -102,7 +103,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
@Override
|
@Override
|
||||||
public List<? extends Action> visit(final Directory d) {
|
public List<? extends Action> visit(final Directory d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -111,7 +112,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -120,7 +120,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final DerivedFile d) {
|
public List<? extends Action> visit(final DerivedFile d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -129,7 +129,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final LocalFile d) {
|
public List<? extends Action> visit(final LocalFile d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
@ -138,7 +138,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
|||||||
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
|
||||||
List<Action> actions = new ArrayList<>();
|
List<Action> actions = new ArrayList<>();
|
||||||
actions.add(ExtractAction.getInstance());
|
actions.add(ExtractAction.getInstance());
|
||||||
actions.add(TagAbstractFileAction.getInstance());
|
actions.add(AddContentTagAction.getInstance());
|
||||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
return actions;
|
return actions;
|
||||||
}
|
}
|
||||||
|
@ -22,6 +22,7 @@ package org.sleuthkit.autopsy.directorytree;
|
|||||||
import java.awt.event.ActionEvent;
|
import java.awt.event.ActionEvent;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.AbstractAction;
|
import javax.swing.AbstractAction;
|
||||||
|
import javax.swing.SwingUtilities;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.windows.Mode;
|
import org.openide.windows.Mode;
|
||||||
import org.openide.windows.WindowManager;
|
import org.openide.windows.WindowManager;
|
||||||
@ -63,12 +64,20 @@ public class NewWindowViewAction extends AbstractAction{
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
DataContentTopComponent dctc = DataContentTopComponent.createUndocked(name, this.contentNode);
|
final DataContentTopComponent dctc = DataContentTopComponent.createUndocked(name, null);
|
||||||
|
|
||||||
Mode m = WindowManager.getDefault().findMode("outputFloat");
|
Mode m = WindowManager.getDefault().findMode("outputFloat");
|
||||||
m.dockInto(dctc);
|
m.dockInto(dctc);
|
||||||
dctc.open();
|
dctc.open();
|
||||||
|
|
||||||
|
// Queue setting the node on the EDT thread to be done later so the dctc
|
||||||
|
// can completely initialize.
|
||||||
|
SwingUtilities.invokeLater(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
dctc.setNode(contentNode);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2013 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.directorytree;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.util.Collection;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import org.openide.util.Utilities;
|
|
||||||
import org.openide.util.actions.Presenter;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
|
||||||
|
|
||||||
public class TagAbstractFileAction extends AbstractAction implements Presenter.Popup {
|
|
||||||
// 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 TagAbstractFileAction instance;
|
|
||||||
|
|
||||||
public static synchronized TagAbstractFileAction getInstance() {
|
|
||||||
if (null == instance) {
|
|
||||||
instance = new TagAbstractFileAction();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TagAbstractFileAction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JMenuItem getPopupPresenter() {
|
|
||||||
return new TagAbstractFileMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
// Do nothing - this action should never be performed.
|
|
||||||
// Submenu actions are invoked instead.
|
|
||||||
}
|
|
||||||
|
|
||||||
private static class TagAbstractFileMenu extends TagMenu {
|
|
||||||
public TagAbstractFileMenu() {
|
|
||||||
super(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class).size() > 1 ? "Tag Files" : "Tag File");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyTag(String tagName, String comment) {
|
|
||||||
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
|
|
||||||
for (AbstractFile file : selectedFiles) {
|
|
||||||
Tags.createTag(file, tagName, comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,71 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2013 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.directorytree;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.util.Collection;
|
|
||||||
import javax.swing.AbstractAction;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import org.openide.util.Utilities;
|
|
||||||
import org.openide.util.actions.Presenter;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
|
|
||||||
public class TagBlackboardArtifactAction extends AbstractAction implements Presenter.Popup {
|
|
||||||
// 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 TagBlackboardArtifactAction instance;
|
|
||||||
|
|
||||||
public static synchronized TagBlackboardArtifactAction getInstance() {
|
|
||||||
if (null == instance) {
|
|
||||||
instance = new TagBlackboardArtifactAction();
|
|
||||||
}
|
|
||||||
return instance;
|
|
||||||
}
|
|
||||||
|
|
||||||
private TagBlackboardArtifactAction() {
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public JMenuItem getPopupPresenter() {
|
|
||||||
return new TagBlackboardArtifactMenu();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
// Do nothing - this action should never be performed.
|
|
||||||
// Submenu actions are invoked instead.
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private static class TagBlackboardArtifactMenu extends TagMenu {
|
|
||||||
public TagBlackboardArtifactMenu() {
|
|
||||||
super(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class).size() > 1 ? "Tag Results" : "Tag Result");
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected void applyTag(String tagName, String comment) {
|
|
||||||
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
|
||||||
for (BlackboardArtifact artifact : selectedArtifacts) {
|
|
||||||
Tags.createTag(artifact, tagName, comment);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,100 +0,0 @@
|
|||||||
/*
|
|
||||||
* Autopsy Forensic Browser
|
|
||||||
*
|
|
||||||
* Copyright 2013 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.directorytree;
|
|
||||||
|
|
||||||
import java.awt.event.ActionEvent;
|
|
||||||
import java.awt.event.ActionListener;
|
|
||||||
import java.util.TreeSet;
|
|
||||||
import javax.swing.JMenu;
|
|
||||||
import javax.swing.JMenuItem;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* The menu that results when one right-clicks on a file or artifact.
|
|
||||||
*/
|
|
||||||
public abstract class TagMenu extends JMenu {
|
|
||||||
public TagMenu(String menuItemText) {
|
|
||||||
super(menuItemText);
|
|
||||||
|
|
||||||
// Create the 'Quick Tag' sub-menu and add it to the tag menu.
|
|
||||||
JMenu quickTagMenu = new JMenu("Quick Tag");
|
|
||||||
add(quickTagMenu);
|
|
||||||
|
|
||||||
// Get the existing tag names.
|
|
||||||
TreeSet<String> tagNames = Tags.getAllTagNames();
|
|
||||||
if (tagNames.isEmpty()) {
|
|
||||||
JMenuItem empty = new JMenuItem("No tags");
|
|
||||||
empty.setEnabled(false);
|
|
||||||
quickTagMenu.add(empty);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add a menu item for each existing tag name to the 'Quick Tag' menu.
|
|
||||||
for (final String tagName : tagNames) {
|
|
||||||
JMenuItem tagNameItem = new JMenuItem(tagName);
|
|
||||||
tagNameItem.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
applyTag(tagName, "");
|
|
||||||
refreshDirectoryTree();
|
|
||||||
}
|
|
||||||
});
|
|
||||||
quickTagMenu.add(tagNameItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
quickTagMenu.addSeparator();
|
|
||||||
|
|
||||||
// Create the 'New Tag' menu item and add it to the 'Quick Tag' menu.
|
|
||||||
JMenuItem newTagMenuItem = new JMenuItem("New Tag");
|
|
||||||
newTagMenuItem.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
String tagName = CreateTagDialog.getNewTagNameDialog(null);
|
|
||||||
if (tagName != null) {
|
|
||||||
applyTag(tagName, "");
|
|
||||||
refreshDirectoryTree();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
quickTagMenu.add(newTagMenuItem);
|
|
||||||
|
|
||||||
// Create the 'Tag and Comment' menu item and add it to the tag menu.
|
|
||||||
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment");
|
|
||||||
tagAndCommentItem.addActionListener(new ActionListener() {
|
|
||||||
@Override
|
|
||||||
public void actionPerformed(ActionEvent e) {
|
|
||||||
TagAndCommentDialog.CommentedTag commentedTag = TagAndCommentDialog.doDialog();
|
|
||||||
if (null != commentedTag) {
|
|
||||||
applyTag(commentedTag.getName(), commentedTag.getComment());
|
|
||||||
refreshDirectoryTree();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
add(tagAndCommentItem);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void refreshDirectoryTree() {
|
|
||||||
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
|
|
||||||
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
|
|
||||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
|
||||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
|
||||||
}
|
|
||||||
|
|
||||||
protected abstract void applyTag(String tagName, String comment);
|
|
||||||
}
|
|
@ -24,7 +24,7 @@ FileSearchTopComponent.dateCheckBox1.text=Date:
|
|||||||
FileSearchTopComponent.dateFiltersButton1.text=Date Filters
|
FileSearchTopComponent.dateFiltersButton1.text=Date Filters
|
||||||
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
||||||
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
|
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
|
||||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL)
|
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
||||||
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
||||||
DateSearchPanel.dateCheckBox.text=Date:
|
DateSearchPanel.dateCheckBox.text=Date:
|
||||||
DateSearchPanel.jLabel4.text=Timezone:
|
DateSearchPanel.jLabel4.text=Timezone:
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Autopsy Forensic Browser
|
* Autopsy Forensic Browser
|
||||||
*
|
*
|
||||||
* Copyright 2011 Basis Technology Corp.
|
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||||
* Contact: carrier <at> sleuthkit <dot> org
|
* Contact: carrier <at> sleuthkit <dot> org
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
|
|||||||
|
|
||||||
String expr = "0";
|
String expr = "0";
|
||||||
if (unknown) {
|
if (unknown) {
|
||||||
expr += " or " + predicateHelper(FileKnown.UKNOWN);
|
expr += " or " + predicateHelper(FileKnown.UNKNOWN);
|
||||||
}
|
}
|
||||||
if (known) {
|
if (known) {
|
||||||
expr += " or " + predicateHelper(FileKnown.KNOWN);
|
expr += " or " + predicateHelper(FileKnown.KNOWN);
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
<?xml version="1.1" encoding="UTF-8" ?>
|
<?xml version="1.0" encoding="UTF-8" ?>
|
||||||
|
|
||||||
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
@ -64,6 +64,9 @@
|
|||||||
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, "{key}")"/>
|
||||||
</Property>
|
</Property>
|
||||||
</Properties>
|
</Properties>
|
||||||
|
<Events>
|
||||||
|
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
|
||||||
|
</Events>
|
||||||
</Component>
|
</Component>
|
||||||
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
|
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
|
||||||
<Properties>
|
<Properties>
|
||||||
|
@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
knownOptionCheckBox.setSelected(true);
|
knownOptionCheckBox.setSelected(true);
|
||||||
knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N
|
knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N
|
||||||
|
knownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() {
|
||||||
|
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||||
|
knownOptionCheckBoxActionPerformed(evt);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
knownBadOptionCheckBox.setSelected(true);
|
knownBadOptionCheckBox.setSelected(true);
|
||||||
knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
|
knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
|
||||||
@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
|||||||
.addComponent(knownBadOptionCheckBox))
|
.addComponent(knownBadOptionCheckBox))
|
||||||
);
|
);
|
||||||
}// </editor-fold>//GEN-END:initComponents
|
}// </editor-fold>//GEN-END:initComponents
|
||||||
|
|
||||||
|
private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed
|
||||||
|
// TODO add your handling code here:
|
||||||
|
}//GEN-LAST:event_knownOptionCheckBoxActionPerformed
|
||||||
|
|
||||||
// Variables declaration - do not modify//GEN-BEGIN:variables
|
// Variables declaration - do not modify//GEN-BEGIN:variables
|
||||||
private javax.swing.JCheckBox knownBadOptionCheckBox;
|
private javax.swing.JCheckBox knownBadOptionCheckBox;
|
||||||
private javax.swing.JCheckBox knownCheckBox;
|
private javax.swing.JCheckBox knownCheckBox;
|
||||||
|
@ -65,6 +65,9 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
|
|||||||
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
|
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
|
||||||
List<IngestModuleAbstract> enabledModules = new ArrayList<>();
|
List<IngestModuleAbstract> enabledModules = new ArrayList<>();
|
||||||
for (String moduleName : enabledModuleNames) {
|
for (String moduleName : enabledModuleNames) {
|
||||||
|
if (moduleName.equals("Thunderbird Parser")) {
|
||||||
|
moduleName = "MBox Parser";
|
||||||
|
}
|
||||||
IngestModuleAbstract moduleFound = null;
|
IngestModuleAbstract moduleFound = null;
|
||||||
for (IngestModuleAbstract module : allModules) {
|
for (IngestModuleAbstract module : allModules) {
|
||||||
if (moduleName.equals(module.getName())) {
|
if (moduleName.equals(module.getName())) {
|
||||||
@ -76,7 +79,7 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
|
|||||||
enabledModules.add(moduleFound);
|
enabledModules.add(moduleFound);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
messages.add("Unable to load " + moduleName + " module");
|
messages.add("Unable to enable ingest module: " + moduleName);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ingestDialogPanel.setEnabledIngestModules(enabledModules);
|
ingestDialogPanel.setEnabledIngestModules(enabledModules);
|
||||||
|
@ -47,6 +47,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
|||||||
private IngestDataSourceWorkerController controller;
|
private IngestDataSourceWorkerController controller;
|
||||||
private final IngestManager manager;
|
private final IngestManager manager;
|
||||||
private final IngestModuleInit init;
|
private final IngestModuleInit init;
|
||||||
|
private boolean inited;
|
||||||
//current method of enqueuing data source ingest modules with locks and internal lock queue
|
//current method of enqueuing data source ingest modules with locks and internal lock queue
|
||||||
//ensures that we init, run and complete a single data source ingest module at a time
|
//ensures that we init, run and complete a single data source ingest module at a time
|
||||||
//uses fairness policy to run them in order enqueued
|
//uses fairness policy to run them in order enqueued
|
||||||
@ -59,6 +60,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
|||||||
this.dataSource = dataSource;
|
this.dataSource = dataSource;
|
||||||
this.module = module;
|
this.module = module;
|
||||||
this.init = init;
|
this.init = init;
|
||||||
|
this.inited = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
PipelineContext<IngestModuleDataSource>getContext() {
|
PipelineContext<IngestModuleDataSource>getContext() {
|
||||||
@ -73,6 +75,20 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
|||||||
return module;
|
return module;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void init() {
|
||||||
|
|
||||||
|
logger.log(Level.INFO, "Initializing module: " + module.getName());
|
||||||
|
try {
|
||||||
|
module.init(init);
|
||||||
|
inited = true;
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
|
||||||
|
//will not run
|
||||||
|
inited = false;
|
||||||
|
throw e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Void doInBackground() throws Exception {
|
protected Void doInBackground() throws Exception {
|
||||||
|
|
||||||
@ -102,15 +118,10 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
|||||||
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
|
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
|
||||||
progress.setDisplayName(displayName);
|
progress.setDisplayName(displayName);
|
||||||
|
|
||||||
logger.log(Level.INFO, "Initializing module: " + module.getName());
|
if (inited == false) {
|
||||||
try {
|
logger.log(Level.INFO, "Module wasn't initialized, will not run: " + module.getName());
|
||||||
module.init(init);
|
|
||||||
} catch (Exception e) {
|
|
||||||
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
|
|
||||||
return Void.TYPE.newInstance();
|
return Void.TYPE.newInstance();
|
||||||
//will not run
|
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.log(Level.INFO, "Starting processing of module: " + module.getName());
|
logger.log(Level.INFO, "Starting processing of module: " + module.getName());
|
||||||
|
|
||||||
controller = new IngestDataSourceWorkerController(this, progress);
|
controller = new IngestDataSourceWorkerController(this, progress);
|
||||||
|
@ -37,6 +37,7 @@ import javax.swing.SwingWorker;
|
|||||||
import org.netbeans.api.progress.ProgressHandle;
|
import org.netbeans.api.progress.ProgressHandle;
|
||||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||||
import org.openide.util.Cancellable;
|
import org.openide.util.Cancellable;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||||
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
||||||
@ -76,6 +77,7 @@ public class IngestManager {
|
|||||||
private IngestModuleLoader moduleLoader = null;
|
private IngestModuleLoader moduleLoader = null;
|
||||||
//property file name id for the module
|
//property file name id for the module
|
||||||
public final static String MODULE_PROPERTIES = "ingest";
|
public final static String MODULE_PROPERTIES = "ingest";
|
||||||
|
private volatile int messageID = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Possible events about ingest modules Event listeners can get the event
|
* Possible events about ingest modules Event listeners can get the event
|
||||||
@ -84,40 +86,52 @@ public class IngestManager {
|
|||||||
public enum IngestModuleEvent {
|
public enum IngestModuleEvent {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event sent when the ingest module has been started processing. Second
|
* Event sent when an ingest module has been started. Second
|
||||||
* argument of the property change fired contains module name String and
|
* argument of the property change is a string form of the module name
|
||||||
* third argument is null.
|
* and the third argument is null.
|
||||||
*/
|
*/
|
||||||
STARTED,
|
STARTED,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event sent when the ingest module has completed processing. Second
|
* Event sent when an ingest module has completed processing by its own
|
||||||
* argument of the property change fired contains module name String and
|
* means. Second
|
||||||
* third argument is null.
|
* argument of the property change is a string form of the module name
|
||||||
|
* and the third argument is null.
|
||||||
*
|
*
|
||||||
* This event is generally used by listeners to perform a final data
|
* This event is generally used by listeners to perform a final data
|
||||||
* view refresh (listeners need to query all data from the blackboard).
|
* view refresh (listeners need to query all data from the blackboard).
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
COMPLETED,
|
COMPLETED,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event sent when the ingest module has stopped processing, and likely
|
* Event sent when an ingest module has stopped processing, and likely
|
||||||
* not all data has been processed. Second argument of the property
|
* not all data has been processed. Second argument of the property
|
||||||
* change fired contains module name String and third argument is null.
|
* change is a string form of the module name and third argument is null.
|
||||||
*/
|
*/
|
||||||
STOPPED,
|
STOPPED,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event sent when ingest module has new data. Second argument of the
|
* Event sent when ingest module posts new data to blackboard or somewhere
|
||||||
|
* else. Second argument of the
|
||||||
* property change fired contains ModuleDataEvent object and third
|
* property change fired contains ModuleDataEvent object and third
|
||||||
* argument is null. The object can contain encapsulated new data
|
* argument is null. The object can contain encapsulated new data
|
||||||
* created by the module. Listener can also query new data as needed.
|
* created by the module. Listener can also query new data as needed.
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
DATA,
|
DATA,
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Event send when content changed, either its attributes changed, or
|
* Event send when content changed, either its attributes changed, or
|
||||||
* new content children have been added
|
* new content children have been added. I.e. from ZIP files or Carved files
|
||||||
*/
|
*/
|
||||||
CONTENT_CHANGED
|
CONTENT_CHANGED,
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Event sent when a file has finished going through a pipeline of modules.
|
||||||
|
* Second argument is the object ID. Third argument is null
|
||||||
|
*/
|
||||||
|
FILE_DONE,
|
||||||
|
|
||||||
};
|
};
|
||||||
//ui
|
//ui
|
||||||
//Initialized by Installer in AWT thread once the Window System is ready
|
//Initialized by Installer in AWT thread once the Window System is ready
|
||||||
@ -183,9 +197,9 @@ public class IngestManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add property change listener to listen to ingest events
|
* Add property change listener to listen to ingest events as defined in IngestModuleEvent.
|
||||||
*
|
*
|
||||||
* @param l PropertyChangeListener to schedule
|
* @param l PropertyChangeListener to register
|
||||||
*/
|
*/
|
||||||
public static synchronized void addPropertyChangeListener(final PropertyChangeListener l) {
|
public static synchronized void addPropertyChangeListener(final PropertyChangeListener l) {
|
||||||
pcs.addPropertyChangeListener(l);
|
pcs.addPropertyChangeListener(l);
|
||||||
@ -195,10 +209,28 @@ public class IngestManager {
|
|||||||
pcs.firePropertyChange(eventType, moduleName, null);
|
pcs.firePropertyChange(eventType, moduleName, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire event when file is done with a pipeline run
|
||||||
|
* @param objId ID of file that is done
|
||||||
|
*/
|
||||||
|
static synchronized void fireFileDone(long objId) {
|
||||||
|
pcs.firePropertyChange(IngestModuleEvent.FILE_DONE.toString(), objId, null);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire event for ModuleDataEvent (when modules post data to blackboard, etc.)
|
||||||
|
* @param moduleDataEvent
|
||||||
|
*/
|
||||||
static synchronized void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
|
static synchronized void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
|
||||||
pcs.firePropertyChange(IngestModuleEvent.DATA.toString(), moduleDataEvent, null);
|
pcs.firePropertyChange(IngestModuleEvent.DATA.toString(), moduleDataEvent, null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Fire event for ModuleContentChanged (when modules create new content that needs to be analyzed)
|
||||||
|
* @param moduleContentEvent
|
||||||
|
*/
|
||||||
static synchronized void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
|
static synchronized void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
|
||||||
pcs.firePropertyChange(IngestModuleEvent.CONTENT_CHANGED.toString(), moduleContentEvent, null);
|
pcs.firePropertyChange(IngestModuleEvent.CONTENT_CHANGED.toString(), moduleContentEvent, null);
|
||||||
}
|
}
|
||||||
@ -280,7 +312,8 @@ public class IngestManager {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starts the needed worker threads.
|
* Starts the File-level Ingest Module pipeline and the Data Source-level Ingest Modules
|
||||||
|
* for the queued up data sources and files.
|
||||||
*
|
*
|
||||||
* if AbstractFile module is still running, do nothing and allow it to
|
* if AbstractFile module is still running, do nothing and allow it to
|
||||||
* consume queue otherwise start /restart AbstractFile worker
|
* consume queue otherwise start /restart AbstractFile worker
|
||||||
@ -291,7 +324,9 @@ public class IngestManager {
|
|||||||
private synchronized void startAll() {
|
private synchronized void startAll() {
|
||||||
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
|
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
|
||||||
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
|
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
|
||||||
|
boolean allInited = true;
|
||||||
|
IngestModuleAbstract failedModule = null;
|
||||||
|
String errorMessage = "";
|
||||||
logger.log(Level.INFO, "DataSource queue: " + dataSourceScheduler.toString());
|
logger.log(Level.INFO, "DataSource queue: " + dataSourceScheduler.toString());
|
||||||
logger.log(Level.INFO, "File queue: " + fileScheduler.toString());
|
logger.log(Level.INFO, "File queue: " + fileScheduler.toString());
|
||||||
|
|
||||||
@ -299,9 +334,15 @@ public class IngestManager {
|
|||||||
ingestMonitor.start();
|
ingestMonitor.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
//image ingesters
|
/////////
|
||||||
|
// Start the data source-level ingest modules
|
||||||
|
List<IngestDataSourceThread> newThreads = new ArrayList<>();
|
||||||
|
|
||||||
// cycle through each data source content in the queue
|
// cycle through each data source content in the queue
|
||||||
while (dataSourceScheduler.hasNext()) {
|
while (dataSourceScheduler.hasNext()) {
|
||||||
|
if (allInited == false) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
//dequeue
|
//dequeue
|
||||||
// get next data source content and set of modules
|
// get next data source content and set of modules
|
||||||
final ScheduledTask<IngestModuleDataSource> dataSourceTask = dataSourceScheduler.next();
|
final ScheduledTask<IngestModuleDataSource> dataSourceTask = dataSourceScheduler.next();
|
||||||
@ -334,14 +375,28 @@ public class IngestManager {
|
|||||||
new PipelineContext<IngestModuleDataSource>(dataSourceTask, getProcessUnallocSpace());
|
new PipelineContext<IngestModuleDataSource>(dataSourceTask, getProcessUnallocSpace());
|
||||||
final IngestDataSourceThread newDataSourceWorker = new IngestDataSourceThread(this,
|
final IngestDataSourceThread newDataSourceWorker = new IngestDataSourceThread(this,
|
||||||
dataSourcepipelineContext, dataSourceTask.getContent(), taskModule, moduleInit);
|
dataSourcepipelineContext, dataSourceTask.getContent(), taskModule, moduleInit);
|
||||||
|
try {
|
||||||
|
newDataSourceWorker.init();
|
||||||
|
} catch (Exception e) {
|
||||||
|
logger.log(Level.SEVERE, "DataSource ingest module failed init(): " + taskModule.getName(), e);
|
||||||
|
allInited = false;
|
||||||
|
failedModule = taskModule;
|
||||||
|
errorMessage = e.getMessage();
|
||||||
|
break;
|
||||||
|
}
|
||||||
dataSourceIngesters.add(newDataSourceWorker);
|
dataSourceIngesters.add(newDataSourceWorker);
|
||||||
|
// Add the worker to the list of new IngestThreads to be started
|
||||||
|
// if all modules initialize.
|
||||||
|
newThreads.add(newDataSourceWorker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
//wrap the module in a worker, that will run init, process and complete on the module
|
// Check to make sure all modules initialized
|
||||||
newDataSourceWorker.execute();
|
if (allInited == false) {
|
||||||
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), taskModule.getName());
|
displayInitError(failedModule.getName(), errorMessage);
|
||||||
}
|
dataSourceIngesters.removeAll(newThreads);
|
||||||
}
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//AbstractFile ingester
|
//AbstractFile ingester
|
||||||
@ -364,19 +419,54 @@ public class IngestManager {
|
|||||||
stats = new IngestManagerStats();
|
stats = new IngestManagerStats();
|
||||||
abstractFileIngester = new IngestAbstractFileProcessor();
|
abstractFileIngester = new IngestAbstractFileProcessor();
|
||||||
//init all fs modules, everytime new worker starts
|
//init all fs modules, everytime new worker starts
|
||||||
/* @@@ I don't understand why we do an init on each module. Should do only modules
|
|
||||||
* that we are going to be using in the pipeline
|
|
||||||
*/
|
|
||||||
for (IngestModuleAbstractFile s : abstractFileModules) {
|
for (IngestModuleAbstractFile s : abstractFileModules) {
|
||||||
|
if (fileScheduler.hasModuleEnqueued(s) == false) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
IngestModuleInit moduleInit = new IngestModuleInit();
|
IngestModuleInit moduleInit = new IngestModuleInit();
|
||||||
try {
|
try {
|
||||||
s.init(moduleInit);
|
s.init(moduleInit);
|
||||||
} catch (Exception e) {
|
} catch (Exception e) {
|
||||||
logger.log(Level.SEVERE, "File ingest module failed init(): " + s.getName());
|
logger.log(Level.SEVERE, "File ingest module failed init(): " + s.getName(), e);
|
||||||
|
allInited = false;
|
||||||
|
failedModule = s;
|
||||||
|
errorMessage = e.getMessage();
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (allInited) {
|
||||||
|
// Start DataSourceIngestModules
|
||||||
|
for (IngestDataSourceThread dataSourceWorker : newThreads) {
|
||||||
|
dataSourceWorker.execute();
|
||||||
|
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), dataSourceWorker.getModule().getName());
|
||||||
|
}
|
||||||
|
// Start AbstractFileIngestModules
|
||||||
|
if (startAbstractFileIngester) {
|
||||||
abstractFileIngester.execute();
|
abstractFileIngester.execute();
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
displayInitError(failedModule.getName(), errorMessage);
|
||||||
|
dataSourceIngesters.removeAll(newThreads);
|
||||||
|
abstractFileIngester = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Open a dialog box to report an initialization error to the user.
|
||||||
|
*
|
||||||
|
* @param moduleName The name of the module that failed to initialize.
|
||||||
|
* @param errorMessage The message gotten from the exception that was thrown.
|
||||||
|
*/
|
||||||
|
private void displayInitError(String moduleName, String errorMessage) {
|
||||||
|
MessageNotifyUtil.Message.error(
|
||||||
|
"Failed to load " + moduleName + " ingest module.\n\n"
|
||||||
|
+ "No ingest modules will be run. Please disable the module "
|
||||||
|
+ "or fix the error and restart ingest by right clicking on "
|
||||||
|
+ "the data source and selecting Run Ingest Modules.\n\n"
|
||||||
|
+ "Error: " + errorMessage);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -930,11 +1020,15 @@ public class IngestManager {
|
|||||||
logger.log(Level.SEVERE, "Error: out of memory from module: " + module.getName(), e);
|
logger.log(Level.SEVERE, "Error: out of memory from module: " + module.getName(), e);
|
||||||
stats.addError(module);
|
stats.addError(module);
|
||||||
}
|
}
|
||||||
|
|
||||||
} //end for every module
|
} //end for every module
|
||||||
|
|
||||||
//free the internal file resource after done with every module
|
//free the internal file resource after done with every module
|
||||||
fileToProcess.close();
|
fileToProcess.close();
|
||||||
|
|
||||||
|
// notify listeners thsi file is done
|
||||||
|
fireFileDone(fileToProcess.getId());
|
||||||
|
|
||||||
int newTotalEnqueuedFiles = fileScheduler.getFilesEnqueuedEst();
|
int newTotalEnqueuedFiles = fileScheduler.getFilesEnqueuedEst();
|
||||||
if (newTotalEnqueuedFiles > totalEnqueuedFiles) {
|
if (newTotalEnqueuedFiles > totalEnqueuedFiles) {
|
||||||
//update if new enqueued
|
//update if new enqueued
|
||||||
@ -1019,7 +1113,7 @@ public class IngestManager {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Thread that adds content/file and module pairs to queues */
|
/* Thread that adds content/file and module pairs to queues. Starts pipelines when done. */
|
||||||
private class EnqueueWorker extends SwingWorker<Object, Void> {
|
private class EnqueueWorker extends SwingWorker<Object, Void> {
|
||||||
|
|
||||||
private List<IngestModuleAbstract> modules;
|
private List<IngestModuleAbstract> modules;
|
||||||
|
@ -60,9 +60,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
|
|||||||
*
|
*
|
||||||
*/
|
*/
|
||||||
class IngestScheduler {
|
class IngestScheduler {
|
||||||
|
|
||||||
private static IngestScheduler instance;
|
private static IngestScheduler instance;
|
||||||
private static Logger logger = Logger.getLogger(IngestScheduler.class.getName());
|
private static final Logger logger = Logger.getLogger(IngestScheduler.class.getName());
|
||||||
private final DataSourceScheduler dataSourceScheduler = new DataSourceScheduler();
|
private final DataSourceScheduler dataSourceScheduler = new DataSourceScheduler();
|
||||||
private final FileScheduler fileScheduler = new FileScheduler();
|
private final FileScheduler fileScheduler = new FileScheduler();
|
||||||
|
|
||||||
@ -103,12 +102,14 @@ class IngestScheduler {
|
|||||||
*/
|
*/
|
||||||
static class FileScheduler implements Iterator<FileScheduler.ProcessTask> {
|
static class FileScheduler implements Iterator<FileScheduler.ProcessTask> {
|
||||||
//root folders enqueued
|
//root folders enqueued
|
||||||
|
|
||||||
private TreeSet<ProcessTask> rootProcessTasks;
|
private TreeSet<ProcessTask> rootProcessTasks;
|
||||||
|
|
||||||
//stack of current dirs to be processed recursively
|
//stack of current dirs to be processed recursively
|
||||||
private List<ProcessTask> curDirProcessTasks;
|
private List<ProcessTask> curDirProcessTasks;
|
||||||
|
|
||||||
//list of files being processed in the currently processed directory
|
//list of files being processed in the currently processed directory
|
||||||
private LinkedList<ProcessTask> curFileProcessTasks; //need to add to start and end quickly
|
private LinkedList<ProcessTask> curFileProcessTasks; //need to add to start and end quickly
|
||||||
|
|
||||||
//estimated total files to be enqueued for currently scheduled content objects
|
//estimated total files to be enqueued for currently scheduled content objects
|
||||||
private int filesEnqueuedEst;
|
private int filesEnqueuedEst;
|
||||||
private int filesDequeued;
|
private int filesDequeued;
|
||||||
@ -119,9 +120,13 @@ class IngestScheduler {
|
|||||||
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue();
|
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue();
|
||||||
|
|
||||||
private FileScheduler() {
|
private FileScheduler() {
|
||||||
rootProcessTasks = new TreeSet<ProcessTask>(new RootTaskComparator());
|
rootProcessTasks = new TreeSet<>(new RootTaskComparator());
|
||||||
curDirProcessTasks = new ArrayList<ProcessTask>();
|
curDirProcessTasks = new ArrayList<>();
|
||||||
curFileProcessTasks = new LinkedList<ProcessTask>();
|
curFileProcessTasks = new LinkedList<>();
|
||||||
|
resetCounters();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void resetCounters() {
|
||||||
filesEnqueuedEst = 0;
|
filesEnqueuedEst = 0;
|
||||||
filesDequeued = 0;
|
filesDequeued = 0;
|
||||||
}
|
}
|
||||||
@ -186,7 +191,7 @@ class IngestScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get number of files dequeued so far This is reset after the same
|
* Get number of files dequeued so far. This is reset after the same
|
||||||
* content is enqueued that is already in a queue
|
* content is enqueued that is already in a queue
|
||||||
*
|
*
|
||||||
* @return number of files dequeued so far
|
* @return number of files dequeued so far
|
||||||
@ -269,7 +274,7 @@ class IngestScheduler {
|
|||||||
ScheduledTask<IngestModuleAbstractFile> scheduledTask = context.getScheduledTask();
|
ScheduledTask<IngestModuleAbstractFile> scheduledTask = context.getScheduledTask();
|
||||||
final Content scheduledContent = scheduledTask.getContent();
|
final Content scheduledContent = scheduledTask.getContent();
|
||||||
Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor());
|
Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor());
|
||||||
List<AbstractFile> firstLevelFiles = new ArrayList<AbstractFile>();
|
List<AbstractFile> firstLevelFiles = new ArrayList<>();
|
||||||
if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) {
|
if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) {
|
||||||
//add the root, which is a leaf itself
|
//add the root, which is a leaf itself
|
||||||
firstLevelFiles.add((AbstractFile) scheduledContent);
|
firstLevelFiles.add((AbstractFile) scheduledContent);
|
||||||
@ -298,7 +303,7 @@ class IngestScheduler {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
List<ProcessTask> processTasks = new ArrayList<ProcessTask>();
|
List<ProcessTask> processTasks = new ArrayList<>();
|
||||||
for (AbstractFile firstLevelFile : firstLevelFiles) {
|
for (AbstractFile firstLevelFile : firstLevelFiles) {
|
||||||
ProcessTask newTask = new ProcessTask(firstLevelFile, context);
|
ProcessTask newTask = new ProcessTask(firstLevelFile, context);
|
||||||
if (shouldEnqueueTask(newTask)) {
|
if (shouldEnqueueTask(newTask)) {
|
||||||
@ -319,7 +324,7 @@ class IngestScheduler {
|
|||||||
final Content inputContent = task.getContent();
|
final Content inputContent = task.getContent();
|
||||||
|
|
||||||
//remove from root queue
|
//remove from root queue
|
||||||
List<ProcessTask> toRemove = new ArrayList<ProcessTask>();
|
List<ProcessTask> toRemove = new ArrayList<>();
|
||||||
for (ProcessTask pt : rootProcessTasks) {
|
for (ProcessTask pt : rootProcessTasks) {
|
||||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||||
toRemove.add(pt);
|
toRemove.add(pt);
|
||||||
@ -328,7 +333,7 @@ class IngestScheduler {
|
|||||||
rootProcessTasks.removeAll(toRemove);
|
rootProcessTasks.removeAll(toRemove);
|
||||||
|
|
||||||
//remove from dir stack
|
//remove from dir stack
|
||||||
toRemove = new ArrayList<ProcessTask>();
|
toRemove = new ArrayList<>();
|
||||||
for (ProcessTask pt : curDirProcessTasks) {
|
for (ProcessTask pt : curDirProcessTasks) {
|
||||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||||
toRemove.add(pt);
|
toRemove.add(pt);
|
||||||
@ -337,7 +342,7 @@ class IngestScheduler {
|
|||||||
curDirProcessTasks.removeAll(toRemove);
|
curDirProcessTasks.removeAll(toRemove);
|
||||||
|
|
||||||
//remove from file queue
|
//remove from file queue
|
||||||
toRemove = new ArrayList<ProcessTask>();
|
toRemove = new ArrayList<>();
|
||||||
for (ProcessTask pt : curFileProcessTasks) {
|
for (ProcessTask pt : curFileProcessTasks) {
|
||||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||||
toRemove.add(pt);
|
toRemove.add(pt);
|
||||||
@ -419,15 +424,11 @@ class IngestScheduler {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean hasNext() {
|
public synchronized boolean hasNext() {
|
||||||
boolean hasNext = !this.curFileProcessTasks.isEmpty();
|
if (curFileProcessTasks.isEmpty()) {
|
||||||
|
resetCounters();
|
||||||
if (!hasNext) {
|
return false;
|
||||||
//reset counters
|
|
||||||
filesDequeued = 0;
|
|
||||||
filesEnqueuedEst = 0;
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
return hasNext;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -438,52 +439,48 @@ class IngestScheduler {
|
|||||||
|
|
||||||
//dequeue the last in the list
|
//dequeue the last in the list
|
||||||
final ProcessTask task = curFileProcessTasks.pollLast();
|
final ProcessTask task = curFileProcessTasks.pollLast();
|
||||||
|
filesDequeued++;
|
||||||
//continue shifting to file queue until not empty
|
|
||||||
while (curFileProcessTasks.isEmpty()
|
|
||||||
&& !(this.rootProcessTasks.isEmpty() && this.curDirProcessTasks.isEmpty())) {
|
|
||||||
updateQueues();
|
updateQueues();
|
||||||
}
|
|
||||||
|
|
||||||
++filesDequeued;
|
|
||||||
|
|
||||||
return task;
|
return task;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Shuffle the queues so that there are files in the files queue.
|
||||||
|
* @returns true if no more data in queue
|
||||||
|
*/
|
||||||
private synchronized void updateQueues() {
|
private synchronized void updateQueues() {
|
||||||
//if file queue is empty, grab the next one from the dir stack
|
|
||||||
//if dir stack is empty, grab one from root dir queue first
|
|
||||||
//when pop from dir stack, get children of popped, and push them back onto stack
|
|
||||||
|
|
||||||
if (!this.curFileProcessTasks.isEmpty()) {
|
// we loop because we could have a directory that has all files
|
||||||
|
// that do not get enqueued
|
||||||
|
while (true) {
|
||||||
|
// There are files in the queue, we're done
|
||||||
|
if (this.curFileProcessTasks.isEmpty() == false) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
//no file queue tasks
|
// fill in the directory queue if it is empty.
|
||||||
//grab from dir stack, if available
|
|
||||||
if (this.curDirProcessTasks.isEmpty()) {
|
if (this.curDirProcessTasks.isEmpty()) {
|
||||||
//grab from root dir sorted queue
|
// bail out if root is also empty -- we are done
|
||||||
if (!rootProcessTasks.isEmpty()) {
|
if (rootProcessTasks.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
ProcessTask rootTask = this.rootProcessTasks.pollFirst();
|
ProcessTask rootTask = this.rootProcessTasks.pollFirst();
|
||||||
curDirProcessTasks.add(rootTask);
|
curDirProcessTasks.add(rootTask);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (!this.curDirProcessTasks.isEmpty()) {
|
|
||||||
//pop and push AbstractFile directory children if any
|
//pop and push AbstractFile directory children if any
|
||||||
//add the popped and its leaf children onto cur file list
|
//add the popped and its leaf children onto cur file list
|
||||||
ProcessTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1);
|
ProcessTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1);
|
||||||
final AbstractFile parentFile = parentTask.file;
|
final AbstractFile parentFile = parentTask.file;
|
||||||
//add popped to file list
|
|
||||||
|
// add itself to the file list
|
||||||
if (shouldEnqueueTask(parentTask)) {
|
if (shouldEnqueueTask(parentTask)) {
|
||||||
this.curFileProcessTasks.addLast(parentTask);
|
this.curFileProcessTasks.addLast(parentTask);
|
||||||
}
|
}
|
||||||
try {
|
|
||||||
//get children, and if leafs, schedule to file queue
|
|
||||||
//otherwise push to curDir stack
|
|
||||||
|
|
||||||
//TODO use the new more specific method to get list of AbstractFile
|
// add its children to the file and directory lists
|
||||||
|
try {
|
||||||
List<Content> children = parentFile.getChildren();
|
List<Content> children = parentFile.getChildren();
|
||||||
for (Content c : children) {
|
for (Content c : children) {
|
||||||
if (c instanceof AbstractFile) {
|
if (c instanceof AbstractFile) {
|
||||||
@ -492,24 +489,17 @@ class IngestScheduler {
|
|||||||
|
|
||||||
if (childFile.isDir()) {
|
if (childFile.isDir()) {
|
||||||
this.curDirProcessTasks.add(childTask);
|
this.curDirProcessTasks.add(childTask);
|
||||||
} else {
|
}
|
||||||
if (shouldEnqueueTask(childTask)) {
|
else if (shouldEnqueueTask(childTask)) {
|
||||||
this.curFileProcessTasks.addLast(childTask);
|
this.curFileProcessTasks.addLast(childTask);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.SEVERE, "Could not get children of file and update file queues: "
|
logger.log(Level.SEVERE, "Could not get children of file and update file queues: "
|
||||||
+ parentFile.getName(), ex);
|
+ parentFile.getName(), ex);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//logger.info("\nAAA ROOTS " + this.rootProcessTasks);
|
|
||||||
//logger.info("\nAAA STACK " + this.curDirProcessTasks);
|
|
||||||
//logger.info("\nAAA CURFILES " + this.curFileProcessTasks);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -518,8 +508,7 @@ class IngestScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return list of input source contents associated with the file/dir
|
* Return list of content objects that are in the queue to be processed.
|
||||||
* objects in the queue scheduler to be processed.
|
|
||||||
*
|
*
|
||||||
* Helpful to determine whether ingest for particular input Content is
|
* Helpful to determine whether ingest for particular input Content is
|
||||||
* active
|
* active
|
||||||
@ -543,6 +532,11 @@ class IngestScheduler {
|
|||||||
return new ArrayList<Content>(contentSet);
|
return new ArrayList<Content>(contentSet);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Determine if a module is in a pipeline in the queue.
|
||||||
|
* @param module
|
||||||
|
* @return true if it is in the queue.
|
||||||
|
*/
|
||||||
synchronized boolean hasModuleEnqueued(IngestModuleAbstractFile module) {
|
synchronized boolean hasModuleEnqueued(IngestModuleAbstractFile module) {
|
||||||
for (ProcessTask task : rootProcessTasks) {
|
for (ProcessTask task : rootProcessTasks) {
|
||||||
for (IngestModuleAbstractFile m : task.context.getScheduledTask().getModules()) {
|
for (IngestModuleAbstractFile m : task.context.getScheduledTask().getModules()) {
|
||||||
@ -578,8 +572,7 @@ class IngestScheduler {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if the file meets criteria to be enqueued, or is a special file
|
* Check if the file is a special file that we should skip
|
||||||
* that we should skip
|
|
||||||
*
|
*
|
||||||
* @param processTask a task whose file to check if should be queued of
|
* @param processTask a task whose file to check if should be queued of
|
||||||
* skipped
|
* skipped
|
||||||
@ -640,7 +633,6 @@ class IngestScheduler {
|
|||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -702,6 +694,11 @@ class IngestScheduler {
|
|||||||
HIGH_PRI_PATHS.add(Pattern.compile("^ProgramData", Pattern.CASE_INSENSITIVE));
|
HIGH_PRI_PATHS.add(Pattern.compile("^ProgramData", Pattern.CASE_INSENSITIVE));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the scheduling priority for a given file.
|
||||||
|
* @param abstractFile
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
static AbstractFilePriotity.Priority getPriority(final AbstractFile abstractFile) {
|
static AbstractFilePriotity.Priority getPriority(final AbstractFile abstractFile) {
|
||||||
if (!abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
|
if (!abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
|
||||||
//quickly filter out unstructured content
|
//quickly filter out unstructured content
|
||||||
|
@ -110,7 +110,8 @@ public class IngestServices {
|
|||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fire module data event to notify registered module data event listeners
|
* Fire module data event to notify registered module data event listeners that there
|
||||||
|
* is new data of a given type from a module
|
||||||
* @param moduleDataEvent module data event, encapsulating blackboard artifact data
|
* @param moduleDataEvent module data event, encapsulating blackboard artifact data
|
||||||
*/
|
*/
|
||||||
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
|
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
|
||||||
@ -120,6 +121,7 @@ public class IngestServices {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Fire module content event to notify registered module content event listeners
|
* Fire module content event to notify registered module content event listeners
|
||||||
|
* that there is new content (from ZIP file contents, carving, etc.)
|
||||||
* @param moduleContentEvent module content event, encapsulating content changed
|
* @param moduleContentEvent module content event, encapsulating content changed
|
||||||
*/
|
*/
|
||||||
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
|
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
|
||||||
|
@ -6,6 +6,7 @@
|
|||||||
</Properties>
|
</Properties>
|
||||||
<SyntheticProperties>
|
<SyntheticProperties>
|
||||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||||
|
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||||
</SyntheticProperties>
|
</SyntheticProperties>
|
||||||
<AuxValues>
|
<AuxValues>
|
||||||
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>
|
||||||
|
@ -24,6 +24,8 @@ import java.awt.Toolkit;
|
|||||||
import java.awt.event.MouseAdapter;
|
import java.awt.event.MouseAdapter;
|
||||||
import java.awt.event.MouseEvent;
|
import java.awt.event.MouseEvent;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
import java.util.Collections;
|
||||||
|
import java.util.Comparator;
|
||||||
import java.util.EnumMap;
|
import java.util.EnumMap;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
@ -41,8 +43,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
|||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
|
||||||
public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
||||||
private static final Logger logger = Logger.getLogger(ArtifactSelectionDialog.class.getName());
|
|
||||||
private static ArtifactSelectionDialog instance;
|
|
||||||
private ArtifactModel model;
|
private ArtifactModel model;
|
||||||
private ArtifactRenderer renderer;
|
private ArtifactRenderer renderer;
|
||||||
|
|
||||||
@ -66,18 +66,24 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
|||||||
try {
|
try {
|
||||||
ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotReport = new ArrayList();
|
ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotReport = new ArrayList();
|
||||||
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
|
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
|
||||||
|
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); // Obsolete artifact type
|
||||||
|
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); // Obsolete artifact type
|
||||||
|
|
||||||
artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse();
|
artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse();
|
||||||
|
|
||||||
artifacts.removeAll(doNotReport);
|
artifacts.removeAll(doNotReport);
|
||||||
|
Collections.sort(artifacts, new Comparator<BlackboardArtifact.ARTIFACT_TYPE>() {
|
||||||
|
@Override
|
||||||
|
public int compare(ARTIFACT_TYPE o1, ARTIFACT_TYPE o2) {
|
||||||
|
return o1.getDisplayName().compareTo(o2.getDisplayName());
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
artifactStates = new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, Boolean>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
artifactStates = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class);
|
||||||
for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) {
|
for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) {
|
||||||
artifactStates.put(type, Boolean.TRUE);
|
artifactStates.put(type, Boolean.TRUE);
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage());
|
Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage());
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,27 +106,6 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Returns a list of the artifact types we want to report on.
|
|
||||||
*/
|
|
||||||
static List<ARTIFACT_TYPE> getImportantArtifactTypes() {
|
|
||||||
List<ARTIFACT_TYPE> types = new ArrayList<ARTIFACT_TYPE>();
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_WEB_COOKIE);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_WEB_HISTORY);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_HASHSET_HIT);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_METADATA_EXIF);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_TAG_FILE);
|
|
||||||
types.add(ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
|
||||||
return types;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Display this dialog, and return the selected artifacts.
|
* Display this dialog, and return the selected artifacts.
|
||||||
*/
|
*/
|
||||||
@ -288,7 +273,5 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
|||||||
}
|
}
|
||||||
return new JLabel();
|
return new JLabel();
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -30,3 +30,13 @@ ReportProgressPanel.processingLabel.text=processingLabel
|
|||||||
ReportGenerationPanel.titleLabel.text=Report Generation Progress
|
ReportGenerationPanel.titleLabel.text=Report Generation Progress
|
||||||
ReportVisualPanel2.taggedResultsRadioButton.text=Tagged Results
|
ReportVisualPanel2.taggedResultsRadioButton.text=Tagged Results
|
||||||
ReportVisualPanel2.allResultsRadioButton.text=All Results
|
ReportVisualPanel2.allResultsRadioButton.text=All Results
|
||||||
|
FileReportConfigurationPanel.jLabel1.text=Select Items to Report:
|
||||||
|
FileReportConfigurationPanel.selectAllButton.text=Select All
|
||||||
|
FileReportConfigurationPanel.deselectAllButton.text=Deselect All
|
||||||
|
FileReportConfigurationDialog.selectAllButton.text=Select All
|
||||||
|
FileReportConfigurationDialog.deselectAllButton.text=Deselect All
|
||||||
|
FileReportConfigurationDialog.jLabel1.text=Select items to include in the File Report
|
||||||
|
FileReportConfigurationDialog.okButton.text=OK
|
||||||
|
ReportWizardFileOptionsVisualPanel.selectAllButton.text=Select All
|
||||||
|
ReportWizardFileOptionsVisualPanel.deselectAllButton.text=Deselect All
|
||||||
|
ReportWizardFileOptionsVisualPanel.jLabel1.text=Select items to include in File Report:
|
||||||
|
138
Core/src/org/sleuthkit/autopsy/report/FileReportDataTypes.java
Executable file
138
Core/src/org/sleuthkit/autopsy/report/FileReportDataTypes.java
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.report;
|
||||||
|
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.TskData;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Represents Column Headers for FileList Reports.
|
||||||
|
*
|
||||||
|
* Encapsulates functionality for getting column values from Files.
|
||||||
|
*
|
||||||
|
* @author jwallace
|
||||||
|
*/
|
||||||
|
public enum FileReportDataTypes {
|
||||||
|
|
||||||
|
NAME("Name") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getName();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FILE_EXT("File Extension") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
String name = file.getName();
|
||||||
|
int extIndex = name.lastIndexOf(".");
|
||||||
|
return (extIndex == -1 ? "" : name.substring(extIndex));
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FILE_TYPE("File Type") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getMetaTypeAsString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
DELETED("Is Deleted") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
if (file.getMetaFlagsAsString().equals(TskData.TSK_FS_META_FLAG_ENUM.UNALLOC.toString())) {
|
||||||
|
return "yes";
|
||||||
|
}
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
},
|
||||||
|
A_TIME("Last Accessed") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getAtimeAsDate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
CR_TIME("File Created") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getCrtimeAsDate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
M_TIME("Last Modified") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getMtimeAsDate();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
SIZE("Size") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return String.valueOf(file.getSize());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
ADDRESS("Address") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return String.valueOf(file.getMetaAddr());
|
||||||
|
}
|
||||||
|
},
|
||||||
|
HASH_VALUE("Hash Value") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getMd5Hash();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
KNOWN_STATUS("Known Status") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getKnown().getName();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
PERMISSIONS("Permissions") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
return file.getModesAsString();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
FULL_PATH("Full Path") {
|
||||||
|
@Override
|
||||||
|
public String getValue(AbstractFile file) {
|
||||||
|
try {
|
||||||
|
return file.getUniquePath();
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
private String name;
|
||||||
|
|
||||||
|
FileReportDataTypes(String name) {
|
||||||
|
this.name = name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getName() {
|
||||||
|
return this.name;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the value of the column from the file.
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
*/
|
||||||
|
public abstract String getValue(AbstractFile file);
|
||||||
|
}
|
60
Core/src/org/sleuthkit/autopsy/report/FileReportModule.java
Executable file
60
Core/src/org/sleuthkit/autopsy/report/FileReportModule.java
Executable file
@ -0,0 +1,60 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.report;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Report Module that reports information on files in a case.
|
||||||
|
*
|
||||||
|
* @author jwallace
|
||||||
|
*/
|
||||||
|
public interface FileReportModule extends ReportModule {
|
||||||
|
/**
|
||||||
|
* Initialize the report which will be stored at the given path.
|
||||||
|
* @param path
|
||||||
|
*/
|
||||||
|
public void startReport(String path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* End the report.
|
||||||
|
* Will be called after the entire report has been written.
|
||||||
|
*/
|
||||||
|
public void endReport();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Start the file list table.
|
||||||
|
* @param headers The columns that should be included in the table.
|
||||||
|
*/
|
||||||
|
public void startTable(List<FileReportDataTypes> headers);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add the given AbstractFile as a row in the table.
|
||||||
|
* Guaranteed to be called between startTable and endTable.
|
||||||
|
* @param toAdd the AbstractFile to be added.
|
||||||
|
* @param columns the columns that should be included
|
||||||
|
*/
|
||||||
|
public void addRow(AbstractFile toAdd, List<FileReportDataTypes> columns);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Close the table.
|
||||||
|
*/
|
||||||
|
public void endTable();
|
||||||
|
}
|
138
Core/src/org/sleuthkit/autopsy/report/FileReportText.java
Executable file
138
Core/src/org/sleuthkit/autopsy/report/FileReportText.java
Executable file
@ -0,0 +1,138 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2013 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.report;
|
||||||
|
|
||||||
|
import java.io.BufferedWriter;
|
||||||
|
import java.io.FileOutputStream;
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.io.OutputStreamWriter;
|
||||||
|
import java.io.Writer;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Iterator;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A Tab-delimited text report of the files in the case.
|
||||||
|
*
|
||||||
|
* @author jwallace
|
||||||
|
*/
|
||||||
|
public class FileReportText implements FileReportModule {
|
||||||
|
private static final Logger logger = Logger.getLogger(FileReportText.class.getName());
|
||||||
|
private String reportPath;
|
||||||
|
private Writer out;
|
||||||
|
private static final String FILE_NAME = "file-report.txt";
|
||||||
|
|
||||||
|
private static FileReportText instance;
|
||||||
|
|
||||||
|
// Get the default implementation of this report
|
||||||
|
public static synchronized FileReportText getDefault() {
|
||||||
|
if (instance == null) {
|
||||||
|
instance = new FileReportText();
|
||||||
|
}
|
||||||
|
return instance;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startReport(String path) {
|
||||||
|
this.reportPath = path + FILE_NAME;
|
||||||
|
try {
|
||||||
|
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(this.reportPath)));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Failed to create report text file", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endReport() {
|
||||||
|
if (out != null) {
|
||||||
|
try {
|
||||||
|
out.close();
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Could not close output writer when ending report.", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private String getTabDelimitedList(List<String> list) {
|
||||||
|
StringBuilder output = new StringBuilder();
|
||||||
|
Iterator<String> it = list.iterator();
|
||||||
|
while(it.hasNext()) {
|
||||||
|
output.append(it.next()).append((it.hasNext() ? "\t" : System.lineSeparator()));
|
||||||
|
}
|
||||||
|
return output.toString();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void startTable(List<FileReportDataTypes> headers) {
|
||||||
|
List<String> titles = new ArrayList<>();
|
||||||
|
for(FileReportDataTypes col : headers) {
|
||||||
|
titles.add(col.getName());
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
out.write(getTabDelimitedList(titles));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error when writing headers to report file: {0}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addRow(AbstractFile toAdd, List<FileReportDataTypes> columns) {
|
||||||
|
List<String> cells = new ArrayList<>();
|
||||||
|
for(FileReportDataTypes type : columns) {
|
||||||
|
cells.add(type.getValue(toAdd));
|
||||||
|
}
|
||||||
|
try {
|
||||||
|
out.write(getTabDelimitedList(cells));
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error when writing row to report file: {0}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void endTable() {
|
||||||
|
try {
|
||||||
|
out.write(System.lineSeparator());
|
||||||
|
} catch (IOException ex) {
|
||||||
|
logger.log(Level.WARNING, "Error when closing table: {0}", ex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getName() {
|
||||||
|
return "Files - Text";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getDescription() {
|
||||||
|
return "A tab delimited text file containing information about files in the case.";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getExtension() {
|
||||||
|
return ".txt";
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getFilePath() {
|
||||||
|
return FILE_NAME;
|
||||||
|
}
|
||||||
|
}
|
@ -161,7 +161,7 @@ public class ReportBodyFile implements GeneralReportModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
String name = "Body File";
|
String name = "TSK Body File";
|
||||||
return name;
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -121,40 +121,6 @@ public class ReportExcel implements TableReportModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a new worksheet for the given data type.
|
|
||||||
* @param name data type name
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startDataType(String name) {
|
|
||||||
// Create a worksheet for the data type (assumed to be an artifact type).
|
|
||||||
name = escapeForExcel(name);
|
|
||||||
sheet = wb.createSheet(name);
|
|
||||||
sheet.setAutobreaks(true);
|
|
||||||
rowIndex = 0;
|
|
||||||
artifactsCount = 0;
|
|
||||||
|
|
||||||
// Add a title row to the worksheet.
|
|
||||||
Row row = sheet.createRow(rowIndex);
|
|
||||||
row.setRowStyle(setStyle);
|
|
||||||
row.createCell(0).setCellValue(name);
|
|
||||||
++rowIndex;
|
|
||||||
|
|
||||||
// Add an artifacts count row. The actual count will be filled in later.
|
|
||||||
row = sheet.createRow(rowIndex);
|
|
||||||
row.setRowStyle(setStyle);
|
|
||||||
row.createCell(0).setCellValue("Number of artifacts:");
|
|
||||||
++rowIndex;
|
|
||||||
|
|
||||||
// Add an empty row as a separator.
|
|
||||||
sheet.createRow(rowIndex);
|
|
||||||
++rowIndex;
|
|
||||||
|
|
||||||
// There will be at least two columns, one each for the artifacts count and its label.
|
|
||||||
sheetColCount = 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new worksheet for the given data type.
|
* Start a new worksheet for the given data type.
|
||||||
* Note: This method is a temporary workaround to avoid modifying the TableReportModule interface.
|
* Note: This method is a temporary workaround to avoid modifying the TableReportModule interface.
|
||||||
@ -162,7 +128,8 @@ public class ReportExcel implements TableReportModule {
|
|||||||
* @param name Name of the data type
|
* @param name Name of the data type
|
||||||
* @param comment Comment on the data type, may be the empty string
|
* @param comment Comment on the data type, may be the empty string
|
||||||
*/
|
*/
|
||||||
public void startDataType(String name, String comment) {
|
@Override
|
||||||
|
public void startDataType(String name, String description) {
|
||||||
// Create a worksheet for the data type (assumed to be an artifact type).
|
// Create a worksheet for the data type (assumed to be an artifact type).
|
||||||
name = escapeForExcel(name);
|
name = escapeForExcel(name);
|
||||||
sheet = wb.createSheet(name);
|
sheet = wb.createSheet(name);
|
||||||
@ -183,10 +150,10 @@ public class ReportExcel implements TableReportModule {
|
|||||||
++rowIndex;
|
++rowIndex;
|
||||||
|
|
||||||
// Add a comment row, if a comment was supplied.
|
// Add a comment row, if a comment was supplied.
|
||||||
if (!comment.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
row = sheet.createRow(rowIndex);
|
row = sheet.createRow(rowIndex);
|
||||||
row.setRowStyle(setStyle);
|
row.setRowStyle(setStyle);
|
||||||
row.createCell(0).setCellValue(comment);
|
row.createCell(0).setCellValue(description);
|
||||||
++rowIndex;
|
++rowIndex;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -310,7 +277,7 @@ public class ReportExcel implements TableReportModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "Excel";
|
return "Results - Excel";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -28,7 +28,6 @@ import java.io.FileNotFoundException;
|
|||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
import java.io.FileInputStream;
|
|
||||||
import java.io.OutputStream;
|
import java.io.OutputStream;
|
||||||
import java.io.OutputStreamWriter;
|
import java.io.OutputStreamWriter;
|
||||||
import java.io.UnsupportedEncodingException;
|
import java.io.UnsupportedEncodingException;
|
||||||
@ -36,7 +35,6 @@ import java.io.Writer;
|
|||||||
import java.text.DateFormat;
|
import java.text.DateFormat;
|
||||||
import java.text.SimpleDateFormat;
|
import java.text.SimpleDateFormat;
|
||||||
import java.util.Date;
|
import java.util.Date;
|
||||||
import java.util.HashSet;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
@ -45,17 +43,15 @@ import org.openide.filesystems.FileUtil;
|
|||||||
import org.openide.util.Exceptions;
|
import org.openide.util.Exceptions;
|
||||||
import org.sleuthkit.autopsy.casemodule.Case;
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.Tags;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
|
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
|
||||||
import org.sleuthkit.autopsy.ingest.IngestManager;
|
import org.sleuthkit.autopsy.ingest.IngestManager;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.Image;
|
import org.sleuthkit.datamodel.Image;
|
||||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.ContentTag;
|
||||||
import org.sleuthkit.datamodel.TskData;
|
|
||||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||||
|
|
||||||
public class ReportHTML implements TableReportModule {
|
public class ReportHTML implements TableReportModule {
|
||||||
@ -91,7 +87,7 @@ public class ReportHTML implements TableReportModule {
|
|||||||
currentCase = Case.getCurrentCase();
|
currentCase = Case.getCurrentCase();
|
||||||
skCase = currentCase.getSleuthkitCase();
|
skCase = currentCase.getSleuthkitCase();
|
||||||
|
|
||||||
dataTypes = new TreeMap<String, Integer>();
|
dataTypes = new TreeMap<>();
|
||||||
|
|
||||||
path = "";
|
path = "";
|
||||||
currentDataType = "";
|
currentDataType = "";
|
||||||
@ -129,10 +125,10 @@ public class ReportHTML implements TableReportModule {
|
|||||||
{
|
{
|
||||||
String iconFilePath;
|
String iconFilePath;
|
||||||
String iconFileName;
|
String iconFileName;
|
||||||
InputStream in = null;
|
InputStream in;
|
||||||
OutputStream output = null;
|
OutputStream output = null;
|
||||||
|
|
||||||
logger.log(Level.INFO, "useDataTypeIcon: dataType = " + dataType);
|
logger.log(Level.INFO, "useDataTypeIcon: dataType = {0}", dataType);
|
||||||
|
|
||||||
// find the artifact with matching display name
|
// find the artifact with matching display name
|
||||||
BlackboardArtifact.ARTIFACT_TYPE artifactType = null;
|
BlackboardArtifact.ARTIFACT_TYPE artifactType = null;
|
||||||
@ -297,39 +293,6 @@ public class ReportHTML implements TableReportModule {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Start a new HTML page for the given data type. Update the output stream to this page,
|
|
||||||
* and setup the web page header.
|
|
||||||
* @param title title of the data type
|
|
||||||
*/
|
|
||||||
@Override
|
|
||||||
public void startDataType(String title) {
|
|
||||||
String fTitle = dataTypeToFileName(title);
|
|
||||||
// Make a new out for this page
|
|
||||||
try {
|
|
||||||
//escape out slashes tha that appear in title
|
|
||||||
|
|
||||||
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + fTitle + getExtension()), "UTF-8"));
|
|
||||||
} catch (FileNotFoundException ex) {
|
|
||||||
logger.log(Level.SEVERE, "File not found: {0}", ex);
|
|
||||||
} catch (UnsupportedEncodingException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Unrecognized encoding");
|
|
||||||
}
|
|
||||||
|
|
||||||
// Write the beginnings of a page
|
|
||||||
// Like <html>, header, title, any content divs
|
|
||||||
try {
|
|
||||||
StringBuilder page = new StringBuilder();
|
|
||||||
page.append("<html>\n<head>\n\t<title>").append(title).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n");
|
|
||||||
page.append("<div id=\"header\">").append(title).append("</div>\n<div id=\"content\">\n");
|
|
||||||
out.write(page.toString());
|
|
||||||
currentDataType = title;
|
|
||||||
rowCount = 0;
|
|
||||||
} catch (IOException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to write page head: {0}", ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start a new HTML page for the given data type. Update the output stream to this page,
|
* Start a new HTML page for the given data type. Update the output stream to this page,
|
||||||
* and setup the web page header.
|
* and setup the web page header.
|
||||||
@ -338,7 +301,8 @@ public class ReportHTML implements TableReportModule {
|
|||||||
* @param name Name of the data type
|
* @param name Name of the data type
|
||||||
* @param comment Comment on the data type, may be the empty string
|
* @param comment Comment on the data type, may be the empty string
|
||||||
*/
|
*/
|
||||||
public void startDataType(String name, String comment) {
|
@Override
|
||||||
|
public void startDataType(String name, String description) {
|
||||||
String title = dataTypeToFileName(name);
|
String title = dataTypeToFileName(name);
|
||||||
try {
|
try {
|
||||||
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8"));
|
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8"));
|
||||||
@ -352,9 +316,9 @@ public class ReportHTML implements TableReportModule {
|
|||||||
StringBuilder page = new StringBuilder();
|
StringBuilder page = new StringBuilder();
|
||||||
page.append("<html>\n<head>\n\t<title>").append(name).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n");
|
page.append("<html>\n<head>\n\t<title>").append(name).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n");
|
||||||
page.append("<div id=\"header\">").append(name).append("</div>\n<div id=\"content\">\n");
|
page.append("<div id=\"header\">").append(name).append("</div>\n<div id=\"content\">\n");
|
||||||
if (!comment.isEmpty()) {
|
if (!description.isEmpty()) {
|
||||||
page.append("<p><strong>");
|
page.append("<p><strong>");
|
||||||
page.append(comment);
|
page.append(description);
|
||||||
page.append("</string></p>\n");
|
page.append("</string></p>\n");
|
||||||
}
|
}
|
||||||
out.write(page.toString());
|
out.write(page.toString());
|
||||||
@ -477,17 +441,17 @@ public class ReportHTML implements TableReportModule {
|
|||||||
* @param columnHeaders column headers
|
* @param columnHeaders column headers
|
||||||
* @param sourceArtifact source blackboard artifact for the table data
|
* @param sourceArtifact source blackboard artifact for the table data
|
||||||
*/
|
*/
|
||||||
public void startTable(List<String> columnHeaders, ARTIFACT_TYPE artifactType) {
|
public void startContentTagsTable(List<String> columnHeaders) {
|
||||||
StringBuilder htmlOutput = new StringBuilder();
|
StringBuilder htmlOutput = new StringBuilder();
|
||||||
htmlOutput.append("<table>\n<thead>\n\t<tr>\n");
|
htmlOutput.append("<table>\n<thead>\n\t<tr>\n");
|
||||||
|
|
||||||
|
// Add the specified columns.
|
||||||
for(String columnHeader : columnHeaders) {
|
for(String columnHeader : columnHeaders) {
|
||||||
htmlOutput.append("\t\t<th>").append(columnHeader).append("</th>\n");
|
htmlOutput.append("\t\t<th>").append(columnHeader).append("</th>\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
// For file tag artifacts, add a column for a hyperlink to a local copy of the tagged file.
|
// Add a column for a hyperlink to a local copy of the tagged content.
|
||||||
if (artifactType.equals(ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
|
||||||
htmlOutput.append("\t\t<th></th>\n");
|
htmlOutput.append("\t\t<th></th>\n");
|
||||||
}
|
|
||||||
|
|
||||||
htmlOutput.append("\t</tr>\n</thead>\n");
|
htmlOutput.append("\t</tr>\n</thead>\n");
|
||||||
|
|
||||||
@ -527,68 +491,29 @@ public class ReportHTML implements TableReportModule {
|
|||||||
try {
|
try {
|
||||||
out.write(builder.toString());
|
out.write(builder.toString());
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Failed to write row to out.");
|
|
||||||
} catch (NullPointerException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Add a row to the current table.
|
|
||||||
*
|
|
||||||
* @param row values for each cell in the row
|
|
||||||
* @param sourceArtifact source blackboard artifact for the table data
|
|
||||||
*/
|
|
||||||
public void addRow(List<String> row, BlackboardArtifact sourceArtifact) {
|
|
||||||
addRowDataForSourceArtifact(row, sourceArtifact);
|
|
||||||
|
|
||||||
StringBuilder builder = new StringBuilder();
|
|
||||||
builder.append("\t<tr>\n");
|
|
||||||
for (String cell : row) {
|
|
||||||
builder.append("\t\t<td>").append(cell).append("</td>\n");
|
|
||||||
}
|
|
||||||
builder.append("\t</tr>\n");
|
|
||||||
rowCount++;
|
|
||||||
|
|
||||||
try {
|
|
||||||
out.write(builder.toString());
|
|
||||||
}
|
|
||||||
catch (IOException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Failed to write row to out.", ex);
|
logger.log(Level.SEVERE, "Failed to write row to out.", ex);
|
||||||
}
|
} catch (NullPointerException ex) {
|
||||||
catch (NullPointerException ex) {
|
|
||||||
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
|
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add cells particular to a type of artifact associated with the row. Assumes that the overload of startTable() that takes an artifact type was called.
|
* Saves a local copy of a tagged file and adds a row with a hyper link to
|
||||||
|
* the file.
|
||||||
*
|
*
|
||||||
* @param row The row.
|
* @param row Values for each data cell in the row.
|
||||||
* @param sourceArtifact The artifact associated with the row.
|
* @param contentTag A content tag to use to make the hyper link.
|
||||||
*/
|
*/
|
||||||
private void addRowDataForSourceArtifact(List<String> row, BlackboardArtifact sourceArtifact) {
|
public void addRowWithTaggedContentHyperlink(List<String> row, ContentTag contentTag) {
|
||||||
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
// Only handling AbstractFiles at present.
|
||||||
BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID);
|
AbstractFile file;
|
||||||
switch (type) {
|
if (contentTag.getContent() instanceof AbstractFile) {
|
||||||
case TSK_TAG_FILE:
|
file = (AbstractFile)contentTag.getContent();
|
||||||
addRowDataForFileTagArtifact(row, sourceArtifact);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Saves a local copy of a tagged file and adds a hyper link to the file to the row.
|
|
||||||
*
|
|
||||||
* @param row The row.
|
|
||||||
* @param sourceArtifact The artifact associated with the row.
|
|
||||||
*/
|
|
||||||
private void addRowDataForFileTagArtifact(List<String> row, BlackboardArtifact sourceArtifact) {
|
|
||||||
try {
|
|
||||||
AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID());
|
|
||||||
|
|
||||||
// Don't make a local copy of the file if it is a directory or unallocated space.
|
// Don't make a local copy of the file if it is a directory or unallocated space.
|
||||||
if (file.isDir() ||
|
if (file.isDir() ||
|
||||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
||||||
@ -600,18 +525,15 @@ public class ReportHTML implements TableReportModule {
|
|||||||
// Make a folder for the local file with the same name as the tag.
|
// Make a folder for the local file with the same name as the tag.
|
||||||
StringBuilder localFilePath = new StringBuilder();
|
StringBuilder localFilePath = new StringBuilder();
|
||||||
localFilePath.append(path);
|
localFilePath.append(path);
|
||||||
HashSet<String> tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact);
|
localFilePath.append(contentTag.getName().getDisplayName());
|
||||||
if (!tagNames.isEmpty()) {
|
|
||||||
localFilePath.append(tagNames.iterator().next());
|
|
||||||
}
|
|
||||||
File localFileFolder = new File(localFilePath.toString());
|
File localFileFolder = new File(localFilePath.toString());
|
||||||
if (!localFileFolder.exists()) {
|
if (!localFileFolder.exists()) {
|
||||||
localFileFolder.mkdirs();
|
localFileFolder.mkdirs();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness.
|
// Construct a file name for the local file that incorporates the file id to ensure uniqueness.
|
||||||
String fileName = file.getName();
|
String fileName = file.getName();
|
||||||
String objectIdSuffix = "_" + sourceArtifact.getObjectID();
|
String objectIdSuffix = "_" + file.getId();
|
||||||
int lastDotIndex = fileName.lastIndexOf(".");
|
int lastDotIndex = fileName.lastIndexOf(".");
|
||||||
if (lastDotIndex != -1 && lastDotIndex != 0) {
|
if (lastDotIndex != -1 && lastDotIndex != 0) {
|
||||||
// The file name has a conventional extension. Insert the object id before the '.' of the extension.
|
// The file name has a conventional extension. Insert the object id before the '.' of the extension.
|
||||||
@ -638,10 +560,23 @@ public class ReportHTML implements TableReportModule {
|
|||||||
localFileLink.append(localFilePath.toString());
|
localFileLink.append(localFilePath.toString());
|
||||||
localFileLink.append("\">View File</a>");
|
localFileLink.append("\">View File</a>");
|
||||||
row.add(localFileLink.toString());
|
row.add(localFileLink.toString());
|
||||||
|
|
||||||
|
StringBuilder builder = new StringBuilder();
|
||||||
|
builder.append("\t<tr>\n");
|
||||||
|
for (String cell : row) {
|
||||||
|
builder.append("\t\t<td>").append(cell).append("</td>\n");
|
||||||
}
|
}
|
||||||
catch (TskCoreException ex) {
|
builder.append("\t</tr>\n");
|
||||||
logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex);
|
rowCount++;
|
||||||
row.add("");
|
|
||||||
|
try {
|
||||||
|
out.write(builder.toString());
|
||||||
|
}
|
||||||
|
catch (IOException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Failed to write row to out.", ex);
|
||||||
|
}
|
||||||
|
catch (NullPointerException ex) {
|
||||||
|
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -665,7 +600,7 @@ public class ReportHTML implements TableReportModule {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public String getName() {
|
public String getName() {
|
||||||
return "HTML";
|
return "Results - HTML";
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -704,11 +639,11 @@ public class ReportHTML implements TableReportModule {
|
|||||||
"table tr:nth-child(even) td {background: #f3f3f3;}";
|
"table tr:nth-child(even) td {background: #f3f3f3;}";
|
||||||
cssOut.write(css);
|
cssOut.write(css);
|
||||||
} catch (FileNotFoundException ex) {
|
} catch (FileNotFoundException ex) {
|
||||||
logger.log(Level.SEVERE, "Could not find index.css file to write to.");
|
logger.log(Level.SEVERE, "Could not find index.css file to write to.", ex);
|
||||||
} catch (UnsupportedEncodingException ex) {
|
} catch (UnsupportedEncodingException ex) {
|
||||||
logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css.");
|
logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css.", ex);
|
||||||
} catch (IOException ex) {
|
} catch (IOException ex) {
|
||||||
logger.log(Level.SEVERE, "Error creating Writer for index.css.");
|
logger.log(Level.SEVERE, "Error creating Writer for index.css.", ex);
|
||||||
} finally {
|
} finally {
|
||||||
try {
|
try {
|
||||||
if(cssOut != null) {
|
if(cssOut != null) {
|
||||||
|
@ -23,37 +23,30 @@
|
|||||||
package org.sleuthkit.autopsy.report;
|
package org.sleuthkit.autopsy.report;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Interface extended by TableReportModule and GeneralReportModule.
|
* Interface got report modules that plug in to the reporting infrastructure.
|
||||||
* Contains vital report information to be used by every report.
|
|
||||||
*/
|
*/
|
||||||
public interface ReportModule {
|
public interface ReportModule {
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a basic string name for the report. What is 'officially' titled.
|
* Get the name of the report this module generates.
|
||||||
*
|
|
||||||
* @return the report name
|
|
||||||
*/
|
*/
|
||||||
public String getName();
|
public String getName();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns a one line user friendly description of the type of report this
|
* Gets a one-line, user friendly description of the type of report this
|
||||||
* module generates
|
* module generates.
|
||||||
* @return user-friendly report description
|
|
||||||
*/
|
*/
|
||||||
public String getDescription();
|
public String getDescription();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the extension that is used for the report
|
* Gets the extension of the report file, if any, generated by this module.
|
||||||
*
|
* @return File name extension, may be null.
|
||||||
* @return String the extension the file will be saved as
|
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
public String getExtension();
|
public String getExtension();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns the path to the main (or only) file for the report.
|
* Gets the path of the report file, if any, generated by this module.
|
||||||
*
|
* @return File path, may be null.
|
||||||
* @return String path to the report file
|
|
||||||
*/
|
*/
|
||||||
public String getFilePath();
|
public String getFilePath();
|
||||||
}
|
}
|
@ -48,16 +48,17 @@ public class ReportProgressPanel extends javax.swing.JPanel {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void customInit(String reportName, String reportPath) {
|
private void customInit(String reportName, String reportPath) {
|
||||||
reportLabel.setText(reportName);
|
|
||||||
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
|
|
||||||
pathLabel.setToolTipText(reportPath);
|
|
||||||
|
|
||||||
reportProgressBar.setIndeterminate(true);
|
reportProgressBar.setIndeterminate(true);
|
||||||
reportProgressBar.setMaximum(100);
|
reportProgressBar.setMaximum(100);
|
||||||
|
|
||||||
|
reportLabel.setText(reportName);
|
||||||
processingLabel.setText("Queuing...");
|
processingLabel.setText("Queuing...");
|
||||||
STATUS = ReportStatus.QUEUING;
|
STATUS = ReportStatus.QUEUING;
|
||||||
|
|
||||||
|
if (reportPath != null) {
|
||||||
|
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
|
||||||
|
pathLabel.setToolTipText(reportPath);
|
||||||
|
|
||||||
// Add the "link" effect to the pathLabel
|
// Add the "link" effect to the pathLabel
|
||||||
final String linkPath = reportPath;
|
final String linkPath = reportPath;
|
||||||
pathLabel.addMouseListener(new MouseListener() {
|
pathLabel.addMouseListener(new MouseListener() {
|
||||||
@ -99,6 +100,10 @@ public class ReportProgressPanel extends javax.swing.JPanel {
|
|||||||
|
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
pathLabel.setText("<html><u>No report file</u></html>");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Return a shortened version of the given path.
|
* Return a shortened version of the given path.
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user