mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-11 23:46:15 +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.
|
||||
- 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
|
||||
Content.getUniquePath() shoudl not thrown TskException. We should deal with it in the method.
|
||||
- DataContentViewerHex and Strings can have the public setDataView methods removed in favor of the new private ones
|
||||
- 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:
|
||||
1) Get Java Setup
|
||||
|
||||
1a) Download and install 32-bit version of JDK version 1.7 (32-bit is currently
|
||||
needed even if you have a 64-bit system).
|
||||
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.
|
||||
|
||||
Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support
|
||||
(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.
|
||||
|
||||
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.
|
||||
|
||||
@ -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
|
||||
launching error if you use libewf 1.
|
||||
- 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
|
||||
|
||||
@ -97,13 +100,13 @@ BACKGROUND:
|
||||
Here are some notes to shed some light on what is going on during
|
||||
the build process.
|
||||
|
||||
- NetBeans uses ant to build Autopsy. The build target locates TSK
|
||||
(and LIBEWF) based on the environment variables and copies the
|
||||
needed JAR and library files into the DataModel module in the Autopsy
|
||||
project (see build-unix.xml and build-windows.xml in the root
|
||||
directory for details). If you want to use the debug version of
|
||||
the TSK dll, then edit the copy line in the build-windows.xml file
|
||||
to copy from the Debug folder.
|
||||
- The Sleuth Kit Java datamodel JAR file has native libraries
|
||||
that are copied into it.
|
||||
|
||||
- NetBeans uses ant to build Autopsy. The build target copies the
|
||||
TSK datamodel JAR file into the project. If you want to use the
|
||||
debug version of the TSK dll, then there is a different ant target
|
||||
in TSK to copy the debug versions of the dlls.
|
||||
|
||||
- On a Windows system, the ant target copies all needed libraries
|
||||
to the autopsy folder. On a Unix system, the ant taget copies only
|
||||
|
@ -191,6 +191,7 @@
|
||||
</dependency>
|
||||
</module-dependencies>
|
||||
<public-packages>
|
||||
<package>org.sleuthkit.autopsy.actions</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule</package>
|
||||
<package>org.sleuthkit.autopsy.casemodule.services</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">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -91,7 +91,7 @@
|
||||
<Component class="javax.swing.JButton" name="cancelButton">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -104,7 +104,7 @@
|
||||
<StringArray count="0"/>
|
||||
</Property>
|
||||
<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>
|
||||
</Properties>
|
||||
<AuxValues>
|
||||
@ -114,31 +114,31 @@
|
||||
<Component class="javax.swing.JLabel" name="tagLabel">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JLabel" name="commentLabel">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="commentText">
|
||||
<Properties>
|
||||
<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 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>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JButton" name="newTagButton">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
@ -16,11 +16,13 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
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.ActionMap;
|
||||
import javax.swing.InputMap;
|
||||
@ -29,28 +31,28 @@ import javax.swing.JDialog;
|
||||
import javax.swing.JFrame;
|
||||
import javax.swing.KeyStroke;
|
||||
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;
|
||||
|
||||
/**
|
||||
* Tag dialog for tagging files and results. User enters an optional comment.
|
||||
*/
|
||||
public class TagAndCommentDialog extends JDialog {
|
||||
public class GetTagNameAndCommentDialog extends JDialog {
|
||||
private static final String NO_TAG_NAMES_MESSAGE = "No Tags";
|
||||
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||
private TagNameAndComment tagNameAndComment = null;
|
||||
|
||||
private static final String NO_TAG_MESSAGE = "No Tags";
|
||||
private String tagName = "";
|
||||
private String comment = "";
|
||||
|
||||
public static class CommentedTag {
|
||||
private String name;
|
||||
public static class TagNameAndComment {
|
||||
private TagName tagName;
|
||||
private String comment;
|
||||
|
||||
CommentedTag(String name, String comment) {
|
||||
this.name = name;
|
||||
private TagNameAndComment(TagName tagName, String comment) {
|
||||
this.tagName = tagName;
|
||||
this.comment = comment;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
public TagName getTagName() {
|
||||
return tagName;
|
||||
}
|
||||
|
||||
public String getComment() {
|
||||
@ -58,25 +60,16 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}
|
||||
}
|
||||
|
||||
public static CommentedTag doDialog() {
|
||||
TagAndCommentDialog dialog = new TagAndCommentDialog();
|
||||
if (!dialog.tagName.isEmpty()) {
|
||||
return new CommentedTag(dialog.tagName, dialog.comment);
|
||||
}
|
||||
else {
|
||||
return null;
|
||||
}
|
||||
public static TagNameAndComment doDialog() {
|
||||
GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog();
|
||||
return dialog.tagNameAndComment;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates new form TagDialog
|
||||
*/
|
||||
private TagAndCommentDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
|
||||
|
||||
private GetTagNameAndCommentDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||
initComponents();
|
||||
|
||||
// Close the dialog when Esc is pressed
|
||||
// Set up the dialog to close when Esc is pressed.
|
||||
String cancelName = "cancel";
|
||||
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
|
||||
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
|
||||
TreeSet<String> tags = Tags.getAllTagNames();
|
||||
|
||||
// if there are no tags, add the NO_TAG_MESSAGE
|
||||
if (tags.isEmpty()) {
|
||||
tags.add(NO_TAG_MESSAGE);
|
||||
// Populate the combo box with the available tag names and save the
|
||||
// tag name DTOs to be enable to return the one the user selects.
|
||||
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
|
||||
List<TagName> currentTagNames = null;
|
||||
try {
|
||||
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
|
||||
for (String tag : tags) {
|
||||
tagCombo.addItem(tag);
|
||||
}
|
||||
|
||||
//center it
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
|
||||
setVisible(true); // blocks
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent 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() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent 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.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N
|
||||
commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // 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() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
newTagButtonActionPerformed(evt);
|
||||
@ -212,27 +211,26 @@ public class TagAndCommentDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
tagName = (String)tagCombo.getSelectedItem();
|
||||
comment = commentText.getText();
|
||||
tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText());
|
||||
dispose();
|
||||
}//GEN-LAST:event_okButtonActionPerformed
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
tagNameAndComment = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
/**
|
||||
* Closes the dialog
|
||||
*/
|
||||
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
|
||||
tagNameAndComment = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_closeDialog
|
||||
|
||||
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
|
||||
String newTagName = CreateTagDialog.getNewTagNameDialog(null);
|
||||
TagName newTagName = GetTagNameDialog.doDialog();
|
||||
if (newTagName != null) {
|
||||
tagCombo.addItem(newTagName);
|
||||
tagCombo.setSelectedItem(newTagName);
|
||||
tagNames.put(newTagName.getDisplayName(), newTagName);
|
||||
tagCombo.addItem(newTagName.getDisplayName());
|
||||
tagCombo.setSelectedItem(newTagName.getDisplayName());
|
||||
}
|
||||
}//GEN-LAST:event_newTagButtonActionPerformed
|
||||
|
@ -72,7 +72,7 @@
|
||||
<Component class="javax.swing.JButton" name="cancelButton">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -82,7 +82,7 @@
|
||||
<Component class="javax.swing.JButton" name="okButton">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
||||
@ -124,7 +124,7 @@
|
||||
<Component class="javax.swing.JLabel" name="preexistingLabel">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
</Component>
|
||||
@ -133,7 +133,7 @@
|
||||
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
|
||||
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
|
||||
<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>
|
||||
</Border>
|
||||
</Property>
|
||||
@ -168,14 +168,14 @@
|
||||
<Component class="javax.swing.JLabel" name="tagNameLabel">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
</Component>
|
||||
<Component class="javax.swing.JTextField" name="tagNameField">
|
||||
<Properties>
|
||||
<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>
|
||||
</Properties>
|
||||
<Events>
|
@ -16,70 +16,128 @@
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.awt.event.KeyEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
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.JFrame;
|
||||
import javax.swing.JOptionPane;
|
||||
import javax.swing.KeyStroke;
|
||||
import javax.swing.table.AbstractTableModel;
|
||||
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 String newTagName;
|
||||
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||
private TagName tagName = null;
|
||||
|
||||
/**
|
||||
* Creates new form CreateTagDialog
|
||||
*/
|
||||
private CreateTagDialog(JFrame parent) {
|
||||
super(parent, true);
|
||||
init();
|
||||
public static TagName doDialog() {
|
||||
GetTagNameDialog dialog = new GetTagNameDialog();
|
||||
return dialog.tagName;
|
||||
}
|
||||
|
||||
public static String getNewTagNameDialog(JFrame parent) {
|
||||
new CreateTagDialog(parent);
|
||||
return newTagName;
|
||||
}
|
||||
|
||||
private void init() {
|
||||
|
||||
setTitle("Create a new tag");
|
||||
|
||||
private GetTagNameDialog() {
|
||||
super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
|
||||
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
||||
initComponents();
|
||||
|
||||
tagsTable.setModel(new TagsTableModel());
|
||||
tagsTable.setTableHeader(null);
|
||||
// Set up the dialog to close when Esc is pressed.
|
||||
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.setFocusable(false);
|
||||
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
|
||||
|
||||
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
|
||||
|
||||
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize();
|
||||
// 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
|
||||
// Center and show the dialog box.
|
||||
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
|
||||
setVisible(true);
|
||||
}
|
||||
|
||||
private boolean containsIllegalCharacters(String content) {
|
||||
if ((content.contains("\\") || content.contains(":") || content.contains("*")
|
||||
|| content.contains("?") || content.contains("\"") || content.contains("<")
|
||||
|| content.contains(">") || content.contains("|"))) {
|
||||
return true;
|
||||
return (content.contains("\\")||
|
||||
content.contains(":") ||
|
||||
content.contains("*") ||
|
||||
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;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getColumnCount() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getValueAt(int rowIndex, int columnIndex) {
|
||||
return tagNames.get(rowIndex).getDisplayName();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -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() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent 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() {
|
||||
public void actionPerformed(java.awt.event.ActionEvent evt) {
|
||||
okButtonActionPerformed(evt);
|
||||
@ -137,13 +195,13 @@ public class CreateTagDialog extends JDialog {
|
||||
tagsTable.setTableHeader(null);
|
||||
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() {
|
||||
public void keyReleased(java.awt.event.KeyEvent evt) {
|
||||
tagNameFieldKeyReleased(evt);
|
||||
@ -211,20 +269,39 @@ public class CreateTagDialog extends JDialog {
|
||||
}// </editor-fold>//GEN-END:initComponents
|
||||
|
||||
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
|
||||
newTagName = null;
|
||||
tagName = null;
|
||||
dispose();
|
||||
}//GEN-LAST:event_cancelButtonActionPerformed
|
||||
|
||||
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
|
||||
String tagName = tagNameField.getText();
|
||||
if (tagName.isEmpty()) {
|
||||
String tagDisplayName = tagNameField.getText();
|
||||
if (tagDisplayName.isEmpty()) {
|
||||
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: \\ : * ? \" < > |",
|
||||
"Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
||||
} else {
|
||||
newTagName = tagName;
|
||||
dispose();
|
||||
}
|
||||
else if (containsIllegalCharacters(tagDisplayName)) {
|
||||
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
else {
|
||||
tagName = tagNames.get(tagDisplayName);
|
||||
if (tagName == null) {
|
||||
try {
|
||||
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
|
||||
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
|
||||
|
||||
@ -251,32 +328,5 @@ public class CreateTagDialog extends JDialog {
|
||||
private javax.swing.JTable tagsTable;
|
||||
// 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
|
||||
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;
|
||||
|
@ -30,7 +30,7 @@
|
||||
</Group>
|
||||
<Group type="102" alignment="0" 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"/>
|
||||
</Group>
|
||||
<Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/>
|
||||
@ -51,7 +51,7 @@
|
||||
<EmptySpace type="separate" max="-2" attributes="0"/>
|
||||
<Group type="103" groupAlignment="3" 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>
|
||||
<EmptySpace type="unrelated" max="-2" 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();
|
||||
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(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))
|
||||
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
|
||||
.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(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE))
|
||||
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
|
||||
@ -148,7 +148,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
|
||||
.addGap(18, 18, 18)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.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)
|
||||
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
|
||||
.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
|
||||
*
|
||||
* Copyright 2012 Basis Technology Corp.
|
||||
* Copyright 2012-2013 Basis Technology Corp.
|
||||
*
|
||||
* Copyright 2012 42six Solutions.
|
||||
* 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
|
||||
// of services.
|
||||
private List<Closeable> services = new ArrayList<Closeable>();
|
||||
private List<Closeable> services = new ArrayList<>();
|
||||
|
||||
// services
|
||||
private FileManager fileManager;
|
||||
private TagsManager tagsManager;
|
||||
|
||||
public Services(SleuthkitCase tskCase) {
|
||||
this.tskCase = tskCase;
|
||||
//create and initialize FileManager as early as possibly in the new/opened Case
|
||||
fileManager = new FileManager(tskCase);
|
||||
services.add(fileManager);
|
||||
|
||||
tagsManager = new TagsManager(tskCase);
|
||||
services.add(tagsManager);
|
||||
}
|
||||
|
||||
public FileManager getFileManager() {
|
||||
return fileManager;
|
||||
}
|
||||
|
||||
public TagsManager getTagsManager() {
|
||||
return tagsManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
// 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="position" intvalue="902"/>
|
||||
</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">
|
||||
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
|
||||
<attr name="position" intvalue="3075"/>
|
||||
@ -368,7 +373,7 @@
|
||||
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance"/>
|
||||
</file>
|
||||
</folder>
|
||||
<folder name="QuickSearch_hidden" />
|
||||
<folder name="QuickSearch_hidden"/>
|
||||
</folder>
|
||||
|
||||
|
||||
|
@ -257,20 +257,16 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
outputViewPane.setText("");
|
||||
prevPageButton.setEnabled(false);
|
||||
nextPageButton.setEnabled(false);
|
||||
currentNode = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setNode(Node selectedNode) {
|
||||
// @@@ Remove this when the redundant setNode() calls problem is fixed.
|
||||
if (currentNode == selectedNode) {
|
||||
return;
|
||||
}
|
||||
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.
|
||||
if (selectedNode == null) {
|
||||
return;
|
||||
@ -308,8 +304,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
|
||||
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
// @@@ Restore this when the redundant setNode() calls problem is fixed.
|
||||
// resetComponents();
|
||||
resetComponents();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -185,6 +185,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
|
||||
@Override
|
||||
public void resetComponent() {
|
||||
videoPanel.reset();
|
||||
imagePanel.reset();
|
||||
lastFile = null;
|
||||
}
|
||||
|
||||
|
@ -607,8 +607,10 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
* Set number of matches to be displayed in the top right
|
||||
* @param numMatches
|
||||
*/
|
||||
public void setNumMatches(int numMatches) {
|
||||
this.numberMatchLabel.setText(Integer.toString(numMatches));
|
||||
public void setNumMatches(Integer numMatches) {
|
||||
if (this.numberMatchLabel != null) {
|
||||
this.numberMatchLabel.setText(Integer.toString(numMatches));
|
||||
}
|
||||
}
|
||||
|
||||
private class DummyNodeListener implements NodeListener {
|
||||
@ -625,6 +627,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
if (load && containsReal(delta)) {
|
||||
load = false;
|
||||
setupTabs(nme.getNode());
|
||||
updateMatches();
|
||||
}
|
||||
}
|
||||
|
||||
@ -637,8 +640,24 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
|
||||
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
|
||||
public void childrenRemoved(NodeMemberEvent nme) {
|
||||
updateMatches();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -293,6 +293,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
|
||||
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
|
||||
|
||||
if (ov == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
propertiesAcc.clear();
|
||||
|
||||
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
|
||||
@ -339,7 +343,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
|
||||
//int scrollWidth = ttv.getWidth();
|
||||
int margin = 4;
|
||||
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() {
|
||||
if (mediaPlayer != null) {
|
||||
setInfoLabelText("");
|
||||
if (mediaPlayer.getStatus() == Status.PLAYING) {
|
||||
mediaPlayer.stop();
|
||||
}
|
||||
|
@ -105,11 +105,7 @@ public class Installer extends ModuleInstall {
|
||||
}
|
||||
|
||||
final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI",
|
||||
"MenuUI",
|
||||
"MenuItemUI",
|
||||
"CheckBoxMenuItemUI",
|
||||
"RadioButtonMenuItemUI",
|
||||
"PopupMenuUI"};
|
||||
};
|
||||
|
||||
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
|
||||
*
|
||||
|
@ -39,12 +39,6 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
||||
// 32 bit architectures
|
||||
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.
|
||||
*
|
||||
@ -78,10 +72,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
||||
* @return a GstVideoPanel
|
||||
*/
|
||||
private static MediaViewVideoPanel getGstImpl() {
|
||||
if (gstVideoPanel == null) {
|
||||
gstVideoPanel = new GstVideoPanel();
|
||||
}
|
||||
return gstVideoPanel;
|
||||
return new GstVideoPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
@ -90,10 +81,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
|
||||
* @return a FXVideoPanel
|
||||
*/
|
||||
private static MediaViewVideoPanel getFXImpl() {
|
||||
if (fxVideoPanel == null) {
|
||||
fxVideoPanel = new FXVideoPanel();
|
||||
}
|
||||
return fxVideoPanel;
|
||||
return new FXVideoPanel();
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -42,6 +42,7 @@ public class ContextMenuExtensionPoint {
|
||||
if (!providerActions.isEmpty()) {
|
||||
actions.add(null); // Separator to set off this provider's actions.
|
||||
actions.addAll(provider.getActions());
|
||||
actions.add(null); // Separator to set off this provider's actions.
|
||||
}
|
||||
}
|
||||
return actions;
|
||||
|
@ -52,165 +52,168 @@ public class JLnkParser {
|
||||
}
|
||||
}
|
||||
|
||||
public JLNK parse() {
|
||||
ByteBuffer bb = ByteBuffer.wrap(content);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int header = bb.getInt();
|
||||
ByteBuffer linkClassIdentifier = bb.get(new byte[16]);
|
||||
int linkFlags = bb.getInt();
|
||||
int fileAttributes = bb.getInt();
|
||||
long crtime = bb.getLong();
|
||||
long atime = bb.getLong();
|
||||
long mtime = bb.getLong();
|
||||
int fileSize = bb.getInt();
|
||||
int iconIndex = bb.getInt();
|
||||
int showCommand = bb.getInt();
|
||||
short hotkey = bb.getShort();
|
||||
bb.get(new byte[10]); // reserved (???)
|
||||
List<String> linkTargetIdList = new ArrayList<String>();
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) {
|
||||
int idListSize = bb.getShort();
|
||||
int bytesRead = 0;
|
||||
List<byte[]> linkTargetIdListBytes = new ArrayList<byte[]>();
|
||||
while(true) {
|
||||
short itemIdSize = bb.getShort();
|
||||
if(itemIdSize == 0) {
|
||||
bytesRead += 2; // two null bytes to terminate id list
|
||||
break;
|
||||
public JLNK parse() throws JLnkParserException {
|
||||
try {
|
||||
ByteBuffer bb = ByteBuffer.wrap(content);
|
||||
bb.order(ByteOrder.LITTLE_ENDIAN);
|
||||
int header = bb.getInt();
|
||||
ByteBuffer linkClassIdentifier = bb.get(new byte[16]);
|
||||
int linkFlags = bb.getInt();
|
||||
int fileAttributes = bb.getInt();
|
||||
long crtime = bb.getLong();
|
||||
long atime = bb.getLong();
|
||||
long mtime = bb.getLong();
|
||||
int fileSize = bb.getInt();
|
||||
int iconIndex = bb.getInt();
|
||||
int showCommand = bb.getInt();
|
||||
short hotkey = bb.getShort();
|
||||
bb.get(new byte[10]); // reserved (???)
|
||||
List<String> linkTargetIdList = new ArrayList<String>();
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) {
|
||||
int idListSize = bb.getShort();
|
||||
int bytesRead = 0;
|
||||
List<byte[]> linkTargetIdListBytes = new ArrayList<byte[]>();
|
||||
while(true) {
|
||||
short itemIdSize = bb.getShort();
|
||||
if(itemIdSize == 0) {
|
||||
bytesRead += 2; // two null bytes to terminate id list
|
||||
break;
|
||||
}
|
||||
byte[] theArray = new byte[itemIdSize-2];
|
||||
bb.get(theArray); // an idlist data object
|
||||
linkTargetIdListBytes.add(theArray);
|
||||
bytesRead = bytesRead + itemIdSize;
|
||||
}
|
||||
byte[] theArray = new byte[itemIdSize-2];
|
||||
bb.get(theArray); // an idlist data object
|
||||
linkTargetIdListBytes.add(theArray);
|
||||
bytesRead = bytesRead + itemIdSize;
|
||||
linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes);
|
||||
}
|
||||
linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes);
|
||||
}
|
||||
boolean hasUnicodeLocalBaseAndCommonSuffixOffset = false;
|
||||
String localBasePath = null;
|
||||
String commonPathSuffix = null;
|
||||
String localBasePathUnicode = null;
|
||||
String commonPathSuffixUnicode = null;
|
||||
int driveSerialNumber = -1;
|
||||
DriveType driveType = null;
|
||||
String volumeLabel = null;
|
||||
int commonNetworkRelativeLinkFlags = -1;
|
||||
NetworkProviderType networkProviderType = null;
|
||||
boolean unicodeNetAndDeviceName = false;
|
||||
String netName = null;
|
||||
String netNameUnicode = null;
|
||||
String deviceName = null;
|
||||
String deviceNameUnicode = null;
|
||||
boolean hasUnicodeLocalBaseAndCommonSuffixOffset = false;
|
||||
String localBasePath = null;
|
||||
String commonPathSuffix = null;
|
||||
String localBasePathUnicode = null;
|
||||
String commonPathSuffixUnicode = null;
|
||||
int driveSerialNumber = -1;
|
||||
DriveType driveType = null;
|
||||
String volumeLabel = null;
|
||||
int commonNetworkRelativeLinkFlags = -1;
|
||||
NetworkProviderType networkProviderType = null;
|
||||
boolean unicodeNetAndDeviceName = false;
|
||||
String netName = null;
|
||||
String netNameUnicode = null;
|
||||
String deviceName = null;
|
||||
String deviceNameUnicode = null;
|
||||
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasLinkInfo.getFlag()) {
|
||||
int startOfLinkInfo = bb.position();
|
||||
int linkInfoSize = bb.getInt();
|
||||
int linkInfoHeaderSize = bb.getInt();
|
||||
hasUnicodeLocalBaseAndCommonSuffixOffset = linkInfoHeaderSize >= 0x24;
|
||||
int linkInfoFlags = bb.getInt();
|
||||
int volumeIdOffset = bb.getInt();
|
||||
int localBasePathOffset = bb.getInt();
|
||||
int commonNetworkRelativeLinkOffset = bb.getInt();
|
||||
int commonPathSuffixOffset = bb.getInt();
|
||||
int localBasePathOffsetUnicode = 0;
|
||||
int commonPathSuffixOffsetUnicode = 0;
|
||||
if (hasUnicodeLocalBaseAndCommonSuffixOffset) {
|
||||
localBasePathOffsetUnicode = bb.getInt();
|
||||
commonPathSuffixOffsetUnicode = bb.getInt();
|
||||
}
|
||||
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) {
|
||||
bb.position(startOfLinkInfo+volumeIdOffset);
|
||||
int volumeIdSize = bb.getInt();
|
||||
driveType = DriveType.valueOf(bb.getInt());
|
||||
driveSerialNumber = bb.getInt();
|
||||
int volumeLabelOffset = bb.getInt();
|
||||
if (volumeLabelOffset != 0x14) {
|
||||
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffset, false, volumeIdSize - 0x10);
|
||||
} else {
|
||||
int volumeLabelOffsetUnicode = bb.getInt();
|
||||
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffsetUnicode, false, volumeIdSize - 0x14);
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasLinkInfo.getFlag()) {
|
||||
int startOfLinkInfo = bb.position();
|
||||
int linkInfoSize = bb.getInt();
|
||||
int linkInfoHeaderSize = bb.getInt();
|
||||
hasUnicodeLocalBaseAndCommonSuffixOffset = linkInfoHeaderSize >= 0x24;
|
||||
int linkInfoFlags = bb.getInt();
|
||||
int volumeIdOffset = bb.getInt();
|
||||
int localBasePathOffset = bb.getInt();
|
||||
int commonNetworkRelativeLinkOffset = bb.getInt();
|
||||
int commonPathSuffixOffset = bb.getInt();
|
||||
int localBasePathOffsetUnicode = 0;
|
||||
int commonPathSuffixOffsetUnicode = 0;
|
||||
if (hasUnicodeLocalBaseAndCommonSuffixOffset) {
|
||||
localBasePathOffsetUnicode = bb.getInt();
|
||||
commonPathSuffixOffsetUnicode = bb.getInt();
|
||||
}
|
||||
localBasePath = parseLocalBasePath(startOfLinkInfo + localBasePathOffset, false);
|
||||
}
|
||||
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) {
|
||||
bb.position(startOfLinkInfo+commonNetworkRelativeLinkOffset);
|
||||
int commonNetworkRelativeLinkSize = bb.getInt();
|
||||
commonNetworkRelativeLinkFlags = bb.getInt();
|
||||
int netNameOffset = bb.getInt();
|
||||
unicodeNetAndDeviceName = netNameOffset > 0x14;
|
||||
int deviceNameOffset = bb.getInt();
|
||||
int netType = bb.getInt();
|
||||
int netNameOffsetUnicode = 0;
|
||||
int deviceNameOffsetUnicode = 0;
|
||||
if (unicodeNetAndDeviceName) {
|
||||
netNameOffsetUnicode = bb.getInt();
|
||||
deviceNameOffsetUnicode = bb.getInt();
|
||||
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) {
|
||||
bb.position(startOfLinkInfo+volumeIdOffset);
|
||||
int volumeIdSize = bb.getInt();
|
||||
driveType = DriveType.valueOf(bb.getInt());
|
||||
driveSerialNumber = bb.getInt();
|
||||
int volumeLabelOffset = bb.getInt();
|
||||
if (volumeLabelOffset != 0x14) {
|
||||
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffset, false, volumeIdSize - 0x10);
|
||||
} else {
|
||||
int volumeLabelOffsetUnicode = bb.getInt();
|
||||
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffsetUnicode, false, volumeIdSize - 0x14);
|
||||
}
|
||||
localBasePath = parseLocalBasePath(startOfLinkInfo + localBasePathOffset, false);
|
||||
}
|
||||
netName = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffset, false);
|
||||
if (unicodeNetAndDeviceName) {
|
||||
netNameUnicode = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffsetUnicode, true);
|
||||
}
|
||||
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag())
|
||||
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag()) {
|
||||
networkProviderType = LnkEnums.NetworkProviderType.valueOf(netType);
|
||||
}
|
||||
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag())
|
||||
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag()) {
|
||||
deviceName = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffset, false);
|
||||
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) {
|
||||
bb.position(startOfLinkInfo+commonNetworkRelativeLinkOffset);
|
||||
int commonNetworkRelativeLinkSize = bb.getInt();
|
||||
commonNetworkRelativeLinkFlags = bb.getInt();
|
||||
int netNameOffset = bb.getInt();
|
||||
unicodeNetAndDeviceName = netNameOffset > 0x14;
|
||||
int deviceNameOffset = bb.getInt();
|
||||
int netType = bb.getInt();
|
||||
int netNameOffsetUnicode = 0;
|
||||
int deviceNameOffsetUnicode = 0;
|
||||
if (unicodeNetAndDeviceName) {
|
||||
deviceNameUnicode = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffsetUnicode, true);
|
||||
netNameOffsetUnicode = bb.getInt();
|
||||
deviceNameOffsetUnicode = bb.getInt();
|
||||
}
|
||||
netName = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffset, false);
|
||||
if (unicodeNetAndDeviceName) {
|
||||
netNameUnicode = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffsetUnicode, true);
|
||||
}
|
||||
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag())
|
||||
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag()) {
|
||||
networkProviderType = LnkEnums.NetworkProviderType.valueOf(netType);
|
||||
}
|
||||
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag())
|
||||
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag()) {
|
||||
deviceName = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffset, false);
|
||||
if (unicodeNetAndDeviceName) {
|
||||
deviceNameUnicode = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffsetUnicode, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
commonPathSuffix = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffset, false);
|
||||
if (((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
&& hasUnicodeLocalBaseAndCommonSuffixOffset) {
|
||||
localBasePathUnicode = parseLocalBasePath(startOfLinkInfo + localBasePathOffsetUnicode, true);
|
||||
commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true);
|
||||
}
|
||||
|
||||
bb.position(startOfLinkInfo+linkInfoSize);
|
||||
}
|
||||
commonPathSuffix = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffset, false);
|
||||
if (((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
|
||||
&& hasUnicodeLocalBaseAndCommonSuffixOffset) {
|
||||
localBasePathUnicode = parseLocalBasePath(startOfLinkInfo + localBasePathOffsetUnicode, true);
|
||||
commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true);
|
||||
String name = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasName.getFlag()) {
|
||||
name = readStringData(bb);
|
||||
}
|
||||
String relativePath = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasRelativePath.getFlag()) {
|
||||
relativePath = readStringData(bb);
|
||||
}
|
||||
String workingDir = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasWorkingDir.getFlag()) {
|
||||
workingDir = readStringData(bb);
|
||||
}
|
||||
String arguments = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasArguments.getFlag()) {
|
||||
arguments = readStringData(bb);
|
||||
}
|
||||
String iconLocation = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasIconLocation.getFlag()) {
|
||||
iconLocation = readStringData(bb);
|
||||
}
|
||||
|
||||
bb.position(startOfLinkInfo+linkInfoSize);
|
||||
return new JLNK(header, linkClassIdentifier.array(), linkFlags, fileAttributes,
|
||||
crtime, atime, mtime, fileSize, iconIndex, showCommand, hotkey,
|
||||
linkTargetIdList,
|
||||
hasUnicodeLocalBaseAndCommonSuffixOffset, localBasePath,
|
||||
commonPathSuffix, localBasePathUnicode, commonPathSuffixUnicode,
|
||||
name, relativePath, workingDir, arguments, iconLocation, driveSerialNumber,
|
||||
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
|
||||
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
|
||||
deviceName, deviceNameUnicode);
|
||||
} catch (Exception e) {
|
||||
throw new JLnkParserException(e);
|
||||
}
|
||||
String name = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasName.getFlag()) {
|
||||
name = readStringData(bb);
|
||||
}
|
||||
String relativePath = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasRelativePath.getFlag()) {
|
||||
relativePath = readStringData(bb);
|
||||
}
|
||||
String workingDir = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasWorkingDir.getFlag()) {
|
||||
workingDir = readStringData(bb);
|
||||
}
|
||||
String arguments = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasArguments.getFlag()) {
|
||||
arguments = readStringData(bb);
|
||||
}
|
||||
String iconLocation = null;
|
||||
if((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) ==
|
||||
LnkEnums.LinkFlags.HasIconLocation.getFlag()) {
|
||||
iconLocation = readStringData(bb);
|
||||
}
|
||||
|
||||
return new JLNK(header, linkClassIdentifier.array(), linkFlags, fileAttributes,
|
||||
crtime, atime, mtime, fileSize, iconIndex, showCommand, hotkey,
|
||||
linkTargetIdList,
|
||||
hasUnicodeLocalBaseAndCommonSuffixOffset, localBasePath,
|
||||
commonPathSuffix, localBasePathUnicode, commonPathSuffixUnicode,
|
||||
name, relativePath, workingDir, arguments, iconLocation, driveSerialNumber,
|
||||
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
|
||||
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
|
||||
deviceName, deviceNameUnicode);
|
||||
|
||||
}
|
||||
|
||||
private String readStringData(ByteBuffer bb) {
|
||||
@ -337,3 +340,5 @@ public class JLnkParser {
|
||||
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";
|
||||
}
|
||||
},
|
||||
HASHSETS {
|
||||
@Override
|
||||
public String toString() {
|
||||
return "In Hashsets";
|
||||
}
|
||||
},
|
||||
MD5HASH {
|
||||
@Override
|
||||
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_META.toString(), content.getMetaType().toString());
|
||||
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());
|
||||
}
|
||||
|
||||
|
@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children.Keys;
|
||||
import org.openide.nodes.Node;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||
import org.sleuthkit.datamodel.DerivedFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
@ -157,8 +156,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Tags t) {
|
||||
return t.new TagsRootNode();
|
||||
public AbstractNode visit(TagsNodeKey tagsNodeKey) {
|
||||
return new TagsNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode {
|
||||
return "artifact-icon.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -52,7 +52,7 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(EmailExtracted ee);
|
||||
|
||||
T visit(Tags t);
|
||||
T visit(TagsNodeKey tagsNodeKey);
|
||||
|
||||
T visit(DataSources i);
|
||||
|
||||
@ -135,8 +135,8 @@ public interface AutopsyItemVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Tags t) {
|
||||
return defaultVisit(t);
|
||||
public T visit(TagsNodeKey tagsNodeKey) {
|
||||
return defaultVisit(tagsNodeKey);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,6 +19,7 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -45,6 +46,15 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
private Content associated;
|
||||
private List<NodeProperty> customProperties;
|
||||
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
|
||||
@ -107,30 +117,38 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
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
|
||||
if (customProperties != null) {
|
||||
for (NodeProperty np : customProperties) {
|
||||
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;
|
||||
@ -316,11 +334,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
|
||||
return "artifact-icon.png";
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
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
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -109,8 +109,8 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -22,9 +22,9 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Directory;
|
||||
@ -77,7 +77,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
@ -93,7 +93,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
}
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,12 +18,9 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.awt.datatransfer.Transferable;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.util.Lookup;
|
||||
import org.openide.util.datatransfer.PasteType;
|
||||
|
||||
|
||||
/**
|
||||
* Interface for all displayable Nodes
|
||||
@ -38,34 +35,6 @@ public abstract class DisplayableItemNode extends AbstractNode {
|
||||
super(children, lookup);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
abstract public boolean isLeafTypeNode();
|
||||
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* 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.KeywordHitsListNode;
|
||||
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode;
|
||||
import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
|
||||
|
||||
/**
|
||||
* Visitor pattern for DisplayableItemNodes
|
||||
* Visitor pattern implementation for DisplayableItemNodes
|
||||
*/
|
||||
public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
@ -85,11 +83,17 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
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);
|
||||
|
||||
@ -265,18 +269,33 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsRootNode bksrn) {
|
||||
return defaultVisit(bksrn);
|
||||
public T visit(TagsNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsNodeRoot bksnr) {
|
||||
return defaultVisit(bksnr);
|
||||
public T visit(TagNameNode node) {
|
||||
return defaultVisit(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagNodeRoot tnr) {
|
||||
return defaultVisit(tnr);
|
||||
public T visit(ContentTagTypeNode node) {
|
||||
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
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -173,6 +173,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
//flatten all emails
|
||||
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||
for (String account : accounts.keySet()) {
|
||||
Map<String, List<Long>> folders = accounts.get(account);
|
||||
for (String folder : folders.keySet()) {
|
||||
@ -180,7 +181,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
for (long l : messages) {
|
||||
try {
|
||||
//TODO: bulk artifact gettings
|
||||
list.add(skCase.getBlackboardArtifact(l));
|
||||
tempList.add(skCase.getBlackboardArtifact(l));
|
||||
} catch (TskException 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;
|
||||
}
|
||||
|
||||
@ -214,8 +215,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -271,11 +272,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@ -293,6 +289,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -336,11 +337,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
@ -383,14 +379,16 @@ public class EmailExtracted implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||
for (long l : messages) {
|
||||
try {
|
||||
//TODO: bulk artifact gettings
|
||||
list.add(skCase.getBlackboardArtifact(l));
|
||||
tempList.add(skCase.getBlackboardArtifact(l));
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
|
||||
}
|
||||
}
|
||||
list.addAll(tempList);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
}
|
||||
|
@ -22,11 +22,11 @@ import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import javax.swing.Action;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
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.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
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(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
@ -170,13 +170,8 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true; //false;
|
||||
return true;
|
||||
}
|
||||
}
|
@ -111,8 +111,8 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
|
||||
return DisplayableItemNode.TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode {
|
||||
getName()));
|
||||
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
|
||||
public <T> T accept(AutopsyItemVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -113,8 +150,8 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Right click action for this node
|
||||
*
|
||||
@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode<Image> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.sql.ResultSet;
|
||||
import java.sql.SQLException;
|
||||
import java.sql.Statement;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashSet;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.List;
|
||||
@ -28,16 +28,18 @@ import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.logging.Level;
|
||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.ChildFactory;
|
||||
import org.openide.nodes.Children;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskException;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Keyword hits node support
|
||||
@ -169,14 +171,14 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
//logger.info("Process took " + (finish-start) + " ms" );
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -229,11 +231,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
this.children = children;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@ -257,6 +254,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -310,11 +312,6 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.ARTIFACT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@ -327,11 +324,11 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
ss.put(new NodeProperty("List Name",
|
||||
"List Name",
|
||||
"no description",
|
||||
name));
|
||||
getDisplayName()));
|
||||
|
||||
|
||||
ss.put(new NodeProperty("Number of Hits",
|
||||
"Number of Hits",
|
||||
ss.put(new NodeProperty("Files with Hits",
|
||||
"Files with Hits",
|
||||
"no description",
|
||||
children.size()));
|
||||
|
||||
@ -350,20 +347,44 @@ public class KeywordHits implements AutopsyVisitableItem {
|
||||
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifact> list) {
|
||||
List<BlackboardArtifact> tempList = new ArrayList<>();
|
||||
for (long l : children) {
|
||||
try {
|
||||
//TODO: bulk artifact gettings
|
||||
list.add(skCase.getBlackboardArtifact(l));
|
||||
tempList.add(skCase.getBlackboardArtifact(l));
|
||||
} catch (TskException ex) {
|
||||
logger.log(Level.WARNING, "TSK Exception occurred", ex);
|
||||
}
|
||||
}
|
||||
list.addAll(tempList);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
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.ExtractAction;
|
||||
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.TskData;
|
||||
|
||||
@ -63,11 +63,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@ -96,6 +91,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -109,7 +109,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
@ -26,12 +26,11 @@ import java.util.Map;
|
||||
import javax.swing.Action;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE;
|
||||
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.TagAbstractFileAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
|
||||
/**
|
||||
@ -56,11 +55,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected Sheet createSheet() {
|
||||
Sheet s = super.createSheet();
|
||||
@ -93,7 +87,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
|
||||
actionsList.add(ExtractAction.getInstance());
|
||||
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
|
||||
actionsList.add(null); // creates a menu separator
|
||||
actionsList.add(TagAbstractFileAction.getInstance());
|
||||
actionsList.add(AddContentTagAction.getInstance());
|
||||
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actionsList.toArray(new Action[0]);
|
||||
}
|
||||
|
@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -42,8 +42,8 @@ public class RecentFilesNode extends DisplayableItemNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -19,7 +19,6 @@
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.openide.nodes.AbstractNode;
|
||||
import org.openide.nodes.Sheet;
|
||||
import org.openide.util.lookup.Lookups;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
@ -36,13 +35,18 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
new KeywordHits(sleuthkitCase),
|
||||
new HashsetHits(sleuthkitCase),
|
||||
new EmailExtracted(sleuthkitCase),
|
||||
new Tags(sleuthkitCase) //TODO move to the top of the tree
|
||||
new TagsNodeKey()
|
||||
)), Lookups.singleton(NAME));
|
||||
setName(NAME);
|
||||
setDisplayName(NAME);
|
||||
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -63,9 +67,4 @@ public class ResultsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
return s;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.META;
|
||||
}
|
||||
}
|
||||
|
@ -80,16 +80,9 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
||||
if (o instanceof EmailExtracted)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
case TSK_TAG_FILE:
|
||||
if (o instanceof Tags)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof Tags)
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
default:
|
||||
@ -105,7 +98,7 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof EmailExtracted)
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof Tags)
|
||||
else if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
else if (o instanceof ExtractedContent)
|
||||
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");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
|
||||
NAME));
|
||||
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.directorytree.ExtractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
|
||||
import org.sleuthkit.datamodel.VirtualDirectory;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
|
||||
@ -82,7 +81,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
@ -120,11 +118,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
|
||||
return v.visit(this);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return true;
|
||||
|
@ -101,12 +101,12 @@ public class VolumeNode extends AbstractContentNode<Volume> {
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public TYPE getDisplayableItemNodeType() {
|
||||
return TYPE.CONTENT;
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
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=...
|
||||
DirectoryTreeTopComponent.backButton.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;
|
||||
|
||||
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.beans.PropertyVetoException;
|
||||
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.ArtifactTypeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
|
||||
import org.sleuthkit.autopsy.datamodel.LocalFileNode;
|
||||
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
|
||||
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.RecentFilesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.FileTypesNode;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
|
||||
import org.sleuthkit.autopsy.datamodel.TagNameNode;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
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
|
||||
//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
|
||||
// TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals
|
||||
// can be removed.
|
||||
|
||||
List<Action> actions = new ArrayList<>();
|
||||
|
||||
@ -207,8 +211,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
@ -224,8 +228,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
@ -241,8 +245,8 @@ public class DataResultFilterNode extends FilterNode {
|
||||
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
} 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()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
} 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()
|
||||
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
|
||||
actions.add(null); // creates a menu separator
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(TagBlackboardArtifactAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.add(AddBlackboardArtifactTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
}
|
||||
}
|
||||
@ -410,13 +414,18 @@ public class DataResultFilterNode extends FilterNode {
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
public AbstractAction visit(TagNameNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagsNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
public AbstractAction visit(ContentTagTypeNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(BlackboardArtifactTagTypeNode node) {
|
||||
return openChild(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
|
||||
import java.beans.PropertyChangeListener;
|
||||
import java.beans.PropertyChangeSupport;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.LinkedList;
|
||||
import java.util.List;
|
||||
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
|
||||
* be called in the gui thread
|
||||
*/
|
||||
void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
||||
public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
|
||||
//save current selection
|
||||
Node selectedNode = getSelectedNode();
|
||||
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
|
||||
* selected node
|
||||
* Set the selected node using a path to a previously selected node.
|
||||
*
|
||||
* @param path node path with node names
|
||||
* @param rootNodeName name of the root node to match or null if any
|
||||
* @param previouslySelectedNodePath Path to a previously selected node.
|
||||
* @param rootNodeName Name of the root node to match, may be null.
|
||||
*/
|
||||
private void setSelectedNode(final String[] path, final String rootNodeName) {
|
||||
if (path == null) {
|
||||
private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
|
||||
if (previouslySelectedNodePath == null) {
|
||||
return;
|
||||
}
|
||||
SwingUtilities.invokeLater(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) {
|
||||
try {
|
||||
Node newSelection = NodeOp.findPath(em.getRootContext(), path);
|
||||
|
||||
if (newSelection != null) {
|
||||
if (rootNodeName != null) {
|
||||
//called from tree auto refresh context
|
||||
//remove last from backlist, because auto select will result in duplication
|
||||
backList.pollLast();
|
||||
}
|
||||
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection});
|
||||
if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
|
||||
Node selectedNode = null;
|
||||
ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
|
||||
while (null == selectedNode && !selectedNodePath.isEmpty()) {
|
||||
try {
|
||||
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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 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);
|
||||
if (null != selectedNode) {
|
||||
if (rootNodeName != null) {
|
||||
//called from tree auto refresh context
|
||||
//remove last from backlist, because auto select will result in duplication
|
||||
backList.pollLast();
|
||||
}
|
||||
try {
|
||||
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
|
||||
}
|
||||
catch (PropertyVetoException ex) {
|
||||
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -18,6 +18,7 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.directorytree;
|
||||
|
||||
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||
import java.awt.Toolkit;
|
||||
import java.awt.Dimension;
|
||||
import java.awt.Font;
|
||||
@ -102,7 +103,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
@Override
|
||||
public List<? extends Action> visit(final Directory d) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
@ -111,7 +112,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
public List<? extends Action> visit(final VirtualDirectory d) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
@ -120,7 +120,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
public List<? extends Action> visit(final DerivedFile d) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
@ -129,7 +129,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
|
||||
public List<? extends Action> visit(final LocalFile d) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
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) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(ExtractAction.getInstance());
|
||||
actions.add(TagAbstractFileAction.getInstance());
|
||||
actions.add(AddContentTagAction.getInstance());
|
||||
actions.addAll(ContextMenuExtensionPoint.getActions());
|
||||
return actions;
|
||||
}
|
||||
|
@ -22,6 +22,7 @@ package org.sleuthkit.autopsy.directorytree;
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.logging.Level;
|
||||
import javax.swing.AbstractAction;
|
||||
import javax.swing.SwingUtilities;
|
||||
import org.openide.nodes.Node;
|
||||
import org.openide.windows.Mode;
|
||||
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");
|
||||
m.dockInto(dctc);
|
||||
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
|
||||
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
|
||||
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
|
||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL)
|
||||
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
|
||||
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
|
||||
DateSearchPanel.dateCheckBox.text=Date:
|
||||
DateSearchPanel.jLabel4.text=Timezone:
|
||||
|
@ -1,7 +1,7 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2011 Basis Technology Corp.
|
||||
* Copyright 2011 - 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
|
||||
|
||||
String expr = "0";
|
||||
if (unknown) {
|
||||
expr += " or " + predicateHelper(FileKnown.UKNOWN);
|
||||
expr += " or " + predicateHelper(FileKnown.UNKNOWN);
|
||||
}
|
||||
if (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">
|
||||
<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}")"/>
|
||||
</Property>
|
||||
</Properties>
|
||||
<Events>
|
||||
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
|
||||
</Events>
|
||||
</Component>
|
||||
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
|
||||
<Properties>
|
||||
|
@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
||||
|
||||
knownOptionCheckBox.setSelected(true);
|
||||
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.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
|
||||
@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
|
||||
.addComponent(knownBadOptionCheckBox))
|
||||
);
|
||||
}// </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
|
||||
private javax.swing.JCheckBox knownBadOptionCheckBox;
|
||||
private javax.swing.JCheckBox knownCheckBox;
|
||||
|
@ -65,6 +65,9 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
|
||||
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
|
||||
List<IngestModuleAbstract> enabledModules = new ArrayList<>();
|
||||
for (String moduleName : enabledModuleNames) {
|
||||
if (moduleName.equals("Thunderbird Parser")) {
|
||||
moduleName = "MBox Parser";
|
||||
}
|
||||
IngestModuleAbstract moduleFound = null;
|
||||
for (IngestModuleAbstract module : allModules) {
|
||||
if (moduleName.equals(module.getName())) {
|
||||
@ -76,7 +79,7 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
|
||||
enabledModules.add(moduleFound);
|
||||
}
|
||||
else {
|
||||
messages.add("Unable to load " + moduleName + " module");
|
||||
messages.add("Unable to enable ingest module: " + moduleName);
|
||||
}
|
||||
}
|
||||
ingestDialogPanel.setEnabledIngestModules(enabledModules);
|
||||
|
@ -47,6 +47,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
||||
private IngestDataSourceWorkerController controller;
|
||||
private final IngestManager manager;
|
||||
private final IngestModuleInit init;
|
||||
private boolean inited;
|
||||
//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
|
||||
//uses fairness policy to run them in order enqueued
|
||||
@ -59,6 +60,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
||||
this.dataSource = dataSource;
|
||||
this.module = module;
|
||||
this.init = init;
|
||||
this.inited = false;
|
||||
}
|
||||
|
||||
PipelineContext<IngestModuleDataSource>getContext() {
|
||||
@ -73,6 +75,20 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
||||
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
|
||||
protected Void doInBackground() throws Exception {
|
||||
|
||||
@ -102,15 +118,10 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
|
||||
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
|
||||
progress.setDisplayName(displayName);
|
||||
|
||||
logger.log(Level.INFO, "Initializing module: " + module.getName());
|
||||
try {
|
||||
module.init(init);
|
||||
} catch (Exception e) {
|
||||
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
|
||||
if (inited == false) {
|
||||
logger.log(Level.INFO, "Module wasn't initialized, will not run: " + module.getName());
|
||||
return Void.TYPE.newInstance();
|
||||
//will not run
|
||||
}
|
||||
|
||||
logger.log(Level.INFO, "Starting processing of module: " + module.getName());
|
||||
|
||||
controller = new IngestDataSourceWorkerController(this, progress);
|
||||
|
@ -37,6 +37,7 @@ import javax.swing.SwingWorker;
|
||||
import org.netbeans.api.progress.ProgressHandle;
|
||||
import org.netbeans.api.progress.ProgressHandleFactory;
|
||||
import org.openide.util.Cancellable;
|
||||
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.PlatformUtil;
|
||||
import org.sleuthkit.autopsy.coreutils.StopWatch;
|
||||
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
|
||||
@ -76,6 +77,7 @@ public class IngestManager {
|
||||
private IngestModuleLoader moduleLoader = null;
|
||||
//property file name id for the module
|
||||
public final static String MODULE_PROPERTIES = "ingest";
|
||||
private volatile int messageID = 0;
|
||||
|
||||
/**
|
||||
* Possible events about ingest modules Event listeners can get the event
|
||||
@ -84,40 +86,52 @@ public class IngestManager {
|
||||
public enum IngestModuleEvent {
|
||||
|
||||
/**
|
||||
* Event sent when the ingest module has been started processing. Second
|
||||
* argument of the property change fired contains module name String and
|
||||
* third argument is null.
|
||||
* Event sent when an ingest module has been started. Second
|
||||
* argument of the property change is a string form of the module name
|
||||
* and the third argument is null.
|
||||
*/
|
||||
STARTED,
|
||||
|
||||
/**
|
||||
* Event sent when the ingest module has completed processing. Second
|
||||
* argument of the property change fired contains module name String and
|
||||
* third argument is null.
|
||||
* Event sent when an ingest module has completed processing by its own
|
||||
* means. Second
|
||||
* 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
|
||||
* view refresh (listeners need to query all data from the blackboard).
|
||||
*
|
||||
*/
|
||||
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
|
||||
* 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,
|
||||
|
||||
/**
|
||||
* 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
|
||||
* argument is null. The object can contain encapsulated new data
|
||||
* created by the module. Listener can also query new data as needed.
|
||||
*
|
||||
*/
|
||||
DATA,
|
||||
|
||||
/**
|
||||
* 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
|
||||
//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) {
|
||||
pcs.addPropertyChangeListener(l);
|
||||
@ -195,10 +209,28 @@ public class IngestManager {
|
||||
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) {
|
||||
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) {
|
||||
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
|
||||
* consume queue otherwise start /restart AbstractFile worker
|
||||
@ -291,7 +324,9 @@ public class IngestManager {
|
||||
private synchronized void startAll() {
|
||||
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
|
||||
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, "File queue: " + fileScheduler.toString());
|
||||
|
||||
@ -299,9 +334,15 @@ public class IngestManager {
|
||||
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
|
||||
while (dataSourceScheduler.hasNext()) {
|
||||
if (allInited == false) {
|
||||
break;
|
||||
}
|
||||
//dequeue
|
||||
// get next data source content and set of modules
|
||||
final ScheduledTask<IngestModuleDataSource> dataSourceTask = dataSourceScheduler.next();
|
||||
@ -334,16 +375,30 @@ public class IngestManager {
|
||||
new PipelineContext<IngestModuleDataSource>(dataSourceTask, getProcessUnallocSpace());
|
||||
final IngestDataSourceThread newDataSourceWorker = new IngestDataSourceThread(this,
|
||||
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);
|
||||
|
||||
//wrap the module in a worker, that will run init, process and complete on the module
|
||||
newDataSourceWorker.execute();
|
||||
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), taskModule.getName());
|
||||
// Add the worker to the list of new IngestThreads to be started
|
||||
// if all modules initialize.
|
||||
newThreads.add(newDataSourceWorker);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Check to make sure all modules initialized
|
||||
if (allInited == false) {
|
||||
displayInitError(failedModule.getName(), errorMessage);
|
||||
dataSourceIngesters.removeAll(newThreads);
|
||||
return;
|
||||
}
|
||||
|
||||
//AbstractFile ingester
|
||||
boolean startAbstractFileIngester = false;
|
||||
if (fileScheduler.hasNext()) {
|
||||
@ -364,19 +419,54 @@ public class IngestManager {
|
||||
stats = new IngestManagerStats();
|
||||
abstractFileIngester = new IngestAbstractFileProcessor();
|
||||
//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) {
|
||||
if (fileScheduler.hasModuleEnqueued(s) == false) {
|
||||
continue;
|
||||
}
|
||||
IngestModuleInit moduleInit = new IngestModuleInit();
|
||||
try {
|
||||
s.init(moduleInit);
|
||||
} 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;
|
||||
}
|
||||
}
|
||||
abstractFileIngester.execute();
|
||||
}
|
||||
|
||||
if (allInited) {
|
||||
// Start DataSourceIngestModules
|
||||
for (IngestDataSourceThread dataSourceWorker : newThreads) {
|
||||
dataSourceWorker.execute();
|
||||
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), dataSourceWorker.getModule().getName());
|
||||
}
|
||||
// Start AbstractFileIngestModules
|
||||
if (startAbstractFileIngester) {
|
||||
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);
|
||||
stats.addError(module);
|
||||
}
|
||||
|
||||
} //end for every module
|
||||
|
||||
//free the internal file resource after done with every module
|
||||
fileToProcess.close();
|
||||
|
||||
// notify listeners thsi file is done
|
||||
fireFileDone(fileToProcess.getId());
|
||||
|
||||
int newTotalEnqueuedFiles = fileScheduler.getFilesEnqueuedEst();
|
||||
if (newTotalEnqueuedFiles > totalEnqueuedFiles) {
|
||||
//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 List<IngestModuleAbstract> modules;
|
||||
|
@ -60,9 +60,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
|
||||
*
|
||||
*/
|
||||
class IngestScheduler {
|
||||
|
||||
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 FileScheduler fileScheduler = new FileScheduler();
|
||||
|
||||
@ -103,12 +102,14 @@ class IngestScheduler {
|
||||
*/
|
||||
static class FileScheduler implements Iterator<FileScheduler.ProcessTask> {
|
||||
//root folders enqueued
|
||||
|
||||
private TreeSet<ProcessTask> rootProcessTasks;
|
||||
|
||||
//stack of current dirs to be processed recursively
|
||||
private List<ProcessTask> curDirProcessTasks;
|
||||
|
||||
//list of files being processed in the currently processed directory
|
||||
private LinkedList<ProcessTask> curFileProcessTasks; //need to add to start and end quickly
|
||||
|
||||
//estimated total files to be enqueued for currently scheduled content objects
|
||||
private int filesEnqueuedEst;
|
||||
private int filesDequeued;
|
||||
@ -119,9 +120,13 @@ class IngestScheduler {
|
||||
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue();
|
||||
|
||||
private FileScheduler() {
|
||||
rootProcessTasks = new TreeSet<ProcessTask>(new RootTaskComparator());
|
||||
curDirProcessTasks = new ArrayList<ProcessTask>();
|
||||
curFileProcessTasks = new LinkedList<ProcessTask>();
|
||||
rootProcessTasks = new TreeSet<>(new RootTaskComparator());
|
||||
curDirProcessTasks = new ArrayList<>();
|
||||
curFileProcessTasks = new LinkedList<>();
|
||||
resetCounters();
|
||||
}
|
||||
|
||||
private void resetCounters() {
|
||||
filesEnqueuedEst = 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
|
||||
*
|
||||
* @return number of files dequeued so far
|
||||
@ -269,7 +274,7 @@ class IngestScheduler {
|
||||
ScheduledTask<IngestModuleAbstractFile> scheduledTask = context.getScheduledTask();
|
||||
final Content scheduledContent = scheduledTask.getContent();
|
||||
Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor());
|
||||
List<AbstractFile> firstLevelFiles = new ArrayList<AbstractFile>();
|
||||
List<AbstractFile> firstLevelFiles = new ArrayList<>();
|
||||
if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) {
|
||||
//add the root, which is a leaf itself
|
||||
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) {
|
||||
ProcessTask newTask = new ProcessTask(firstLevelFile, context);
|
||||
if (shouldEnqueueTask(newTask)) {
|
||||
@ -319,7 +324,7 @@ class IngestScheduler {
|
||||
final Content inputContent = task.getContent();
|
||||
|
||||
//remove from root queue
|
||||
List<ProcessTask> toRemove = new ArrayList<ProcessTask>();
|
||||
List<ProcessTask> toRemove = new ArrayList<>();
|
||||
for (ProcessTask pt : rootProcessTasks) {
|
||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||
toRemove.add(pt);
|
||||
@ -328,7 +333,7 @@ class IngestScheduler {
|
||||
rootProcessTasks.removeAll(toRemove);
|
||||
|
||||
//remove from dir stack
|
||||
toRemove = new ArrayList<ProcessTask>();
|
||||
toRemove = new ArrayList<>();
|
||||
for (ProcessTask pt : curDirProcessTasks) {
|
||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||
toRemove.add(pt);
|
||||
@ -337,7 +342,7 @@ class IngestScheduler {
|
||||
curDirProcessTasks.removeAll(toRemove);
|
||||
|
||||
//remove from file queue
|
||||
toRemove = new ArrayList<ProcessTask>();
|
||||
toRemove = new ArrayList<>();
|
||||
for (ProcessTask pt : curFileProcessTasks) {
|
||||
if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
|
||||
toRemove.add(pt);
|
||||
@ -419,15 +424,11 @@ class IngestScheduler {
|
||||
|
||||
@Override
|
||||
public synchronized boolean hasNext() {
|
||||
boolean hasNext = !this.curFileProcessTasks.isEmpty();
|
||||
|
||||
if (!hasNext) {
|
||||
//reset counters
|
||||
filesDequeued = 0;
|
||||
filesEnqueuedEst = 0;
|
||||
if (curFileProcessTasks.isEmpty()) {
|
||||
resetCounters();
|
||||
return false;
|
||||
}
|
||||
|
||||
return hasNext;
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -438,52 +439,48 @@ class IngestScheduler {
|
||||
|
||||
//dequeue the last in the list
|
||||
final ProcessTask task = curFileProcessTasks.pollLast();
|
||||
|
||||
//continue shifting to file queue until not empty
|
||||
while (curFileProcessTasks.isEmpty()
|
||||
&& !(this.rootProcessTasks.isEmpty() && this.curDirProcessTasks.isEmpty())) {
|
||||
updateQueues();
|
||||
}
|
||||
|
||||
++filesDequeued;
|
||||
filesDequeued++;
|
||||
updateQueues();
|
||||
|
||||
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() {
|
||||
//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()) {
|
||||
return;
|
||||
}
|
||||
// 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;
|
||||
}
|
||||
|
||||
//no file queue tasks
|
||||
//grab from dir stack, if available
|
||||
if (this.curDirProcessTasks.isEmpty()) {
|
||||
//grab from root dir sorted queue
|
||||
if (!rootProcessTasks.isEmpty()) {
|
||||
// fill in the directory queue if it is empty.
|
||||
if (this.curDirProcessTasks.isEmpty()) {
|
||||
// bail out if root is also empty -- we are done
|
||||
if (rootProcessTasks.isEmpty()) {
|
||||
return;
|
||||
}
|
||||
ProcessTask rootTask = this.rootProcessTasks.pollFirst();
|
||||
curDirProcessTasks.add(rootTask);
|
||||
}
|
||||
}
|
||||
|
||||
if (!this.curDirProcessTasks.isEmpty()) {
|
||||
//pop and push AbstractFile directory children if any
|
||||
//add the popped and its leaf children onto cur file list
|
||||
ProcessTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1);
|
||||
final AbstractFile parentFile = parentTask.file;
|
||||
//add popped to file list
|
||||
|
||||
// add itself to the file list
|
||||
if (shouldEnqueueTask(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();
|
||||
for (Content c : children) {
|
||||
if (c instanceof AbstractFile) {
|
||||
@ -492,24 +489,17 @@ class IngestScheduler {
|
||||
|
||||
if (childFile.isDir()) {
|
||||
this.curDirProcessTasks.add(childTask);
|
||||
} else {
|
||||
if (shouldEnqueueTask(childTask)) {
|
||||
this.curFileProcessTasks.addLast(childTask);
|
||||
}
|
||||
}
|
||||
|
||||
else if (shouldEnqueueTask(childTask)) {
|
||||
this.curFileProcessTasks.addLast(childTask);
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Could not get children of file and update file queues: "
|
||||
+ parentFile.getName(), ex);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
//logger.info("\nAAA ROOTS " + this.rootProcessTasks);
|
||||
//logger.info("\nAAA STACK " + this.curDirProcessTasks);
|
||||
//logger.info("\nAAA CURFILES " + this.curFileProcessTasks);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -518,8 +508,7 @@ class IngestScheduler {
|
||||
}
|
||||
|
||||
/**
|
||||
* Return list of input source contents associated with the file/dir
|
||||
* objects in the queue scheduler to be processed.
|
||||
* Return list of content objects that are in the queue to be processed.
|
||||
*
|
||||
* Helpful to determine whether ingest for particular input Content is
|
||||
* active
|
||||
@ -543,6 +532,11 @@ class IngestScheduler {
|
||||
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) {
|
||||
for (ProcessTask task : rootProcessTasks) {
|
||||
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
|
||||
* that we should skip
|
||||
* Check if the file is a special file that we should skip
|
||||
*
|
||||
* @param processTask a task whose file to check if should be queued of
|
||||
* skipped
|
||||
@ -640,7 +633,6 @@ class IngestScheduler {
|
||||
|
||||
}
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -702,6 +694,11 @@ class IngestScheduler {
|
||||
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) {
|
||||
if (!abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
|
||||
//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
|
||||
*/
|
||||
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
|
||||
@ -120,6 +121,7 @@ public class IngestServices {
|
||||
|
||||
/**
|
||||
* 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
|
||||
*/
|
||||
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
|
||||
|
@ -6,6 +6,7 @@
|
||||
</Properties>
|
||||
<SyntheticProperties>
|
||||
<SyntheticProperty name="formSizePolicy" type="int" value="1"/>
|
||||
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
|
||||
</SyntheticProperties>
|
||||
<AuxValues>
|
||||
<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.MouseEvent;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
import java.util.EnumMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
@ -41,8 +43,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
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 ArtifactRenderer renderer;
|
||||
|
||||
@ -66,18 +66,24 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
||||
try {
|
||||
ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotReport = new ArrayList();
|
||||
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.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) {
|
||||
artifactStates.put(type, Boolean.TRUE);
|
||||
}
|
||||
} catch (TskCoreException ex) {
|
||||
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.
|
||||
*/
|
||||
@ -288,7 +273,5 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
|
||||
}
|
||||
return new JLabel();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -30,3 +30,13 @@ ReportProgressPanel.processingLabel.text=processingLabel
|
||||
ReportGenerationPanel.titleLabel.text=Report Generation Progress
|
||||
ReportVisualPanel2.taggedResultsRadioButton.text=Tagged 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
|
||||
public String getName() {
|
||||
String name = "Body File";
|
||||
String name = "TSK Body File";
|
||||
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.
|
||||
* 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 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).
|
||||
name = escapeForExcel(name);
|
||||
sheet = wb.createSheet(name);
|
||||
@ -183,10 +150,10 @@ public class ReportExcel implements TableReportModule {
|
||||
++rowIndex;
|
||||
|
||||
// Add a comment row, if a comment was supplied.
|
||||
if (!comment.isEmpty()) {
|
||||
if (!description.isEmpty()) {
|
||||
row = sheet.createRow(rowIndex);
|
||||
row.setRowStyle(setStyle);
|
||||
row.createCell(0).setCellValue(comment);
|
||||
row.createCell(0).setCellValue(description);
|
||||
++rowIndex;
|
||||
}
|
||||
|
||||
@ -310,7 +277,7 @@ public class ReportExcel implements TableReportModule {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "Excel";
|
||||
return "Results - Excel";
|
||||
}
|
||||
|
||||
@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.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.FileInputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.OutputStreamWriter;
|
||||
import java.io.UnsupportedEncodingException;
|
||||
@ -36,7 +35,6 @@ import java.io.Writer;
|
||||
import java.text.DateFormat;
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.Date;
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.TreeMap;
|
||||
@ -45,17 +43,15 @@ import org.openide.filesystems.FileUtil;
|
||||
import org.openide.util.Exceptions;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
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.ingest.IngestManager;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.Image;
|
||||
import org.sleuthkit.datamodel.SleuthkitCase;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
|
||||
import org.sleuthkit.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.TskData;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
|
||||
|
||||
public class ReportHTML implements TableReportModule {
|
||||
@ -91,7 +87,7 @@ public class ReportHTML implements TableReportModule {
|
||||
currentCase = Case.getCurrentCase();
|
||||
skCase = currentCase.getSleuthkitCase();
|
||||
|
||||
dataTypes = new TreeMap<String, Integer>();
|
||||
dataTypes = new TreeMap<>();
|
||||
|
||||
path = "";
|
||||
currentDataType = "";
|
||||
@ -129,10 +125,10 @@ public class ReportHTML implements TableReportModule {
|
||||
{
|
||||
String iconFilePath;
|
||||
String iconFileName;
|
||||
InputStream in = null;
|
||||
InputStream in;
|
||||
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
|
||||
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,
|
||||
* and setup the web page header.
|
||||
@ -338,7 +301,8 @@ public class ReportHTML implements TableReportModule {
|
||||
* @param name Name of the data type
|
||||
* @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);
|
||||
try {
|
||||
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();
|
||||
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");
|
||||
if (!comment.isEmpty()) {
|
||||
if (!description.isEmpty()) {
|
||||
page.append("<p><strong>");
|
||||
page.append(comment);
|
||||
page.append(description);
|
||||
page.append("</string></p>\n");
|
||||
}
|
||||
out.write(page.toString());
|
||||
@ -477,17 +441,17 @@ public class ReportHTML implements TableReportModule {
|
||||
* @param columnHeaders column headers
|
||||
* @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();
|
||||
htmlOutput.append("<table>\n<thead>\n\t<tr>\n");
|
||||
|
||||
// Add the specified columns.
|
||||
for(String columnHeader : columnHeaders) {
|
||||
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.
|
||||
if (artifactType.equals(ARTIFACT_TYPE.TSK_TAG_FILE)) {
|
||||
htmlOutput.append("\t\t<th></th>\n");
|
||||
}
|
||||
// Add a column for a hyperlink to a local copy of the tagged content.
|
||||
htmlOutput.append("\t\t<th></th>\n");
|
||||
|
||||
htmlOutput.append("\t</tr>\n</thead>\n");
|
||||
|
||||
@ -527,20 +491,75 @@ public class ReportHTML implements TableReportModule {
|
||||
try {
|
||||
out.write(builder.toString());
|
||||
} catch (IOException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to write row to out.");
|
||||
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.");
|
||||
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a row to the current table.
|
||||
* Saves a local copy of a tagged file and adds a row with a hyper link to
|
||||
* the file.
|
||||
*
|
||||
* @param row values for each cell in the row
|
||||
* @param sourceArtifact source blackboard artifact for the table data
|
||||
* @param row Values for each data cell in the row.
|
||||
* @param contentTag A content tag to use to make the hyper link.
|
||||
*/
|
||||
public void addRow(List<String> row, BlackboardArtifact sourceArtifact) {
|
||||
addRowDataForSourceArtifact(row, sourceArtifact);
|
||||
public void addRowWithTaggedContentHyperlink(List<String> row, ContentTag contentTag) {
|
||||
// Only handling AbstractFiles at present.
|
||||
AbstractFile file;
|
||||
if (contentTag.getContent() instanceof AbstractFile) {
|
||||
file = (AbstractFile)contentTag.getContent();
|
||||
}
|
||||
else {
|
||||
return;
|
||||
}
|
||||
|
||||
// Don't make a local copy of the file if it is a directory or unallocated space.
|
||||
if (file.isDir() ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) {
|
||||
row.add("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a folder for the local file with the same name as the tag.
|
||||
StringBuilder localFilePath = new StringBuilder();
|
||||
localFilePath.append(path);
|
||||
localFilePath.append(contentTag.getName().getDisplayName());
|
||||
File localFileFolder = new File(localFilePath.toString());
|
||||
if (!localFileFolder.exists()) {
|
||||
localFileFolder.mkdirs();
|
||||
}
|
||||
|
||||
// Construct a file name for the local file that incorporates the file id to ensure uniqueness.
|
||||
String fileName = file.getName();
|
||||
String objectIdSuffix = "_" + file.getId();
|
||||
int lastDotIndex = fileName.lastIndexOf(".");
|
||||
if (lastDotIndex != -1 && lastDotIndex != 0) {
|
||||
// The file name has a conventional extension. Insert the object id before the '.' of the extension.
|
||||
fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length());
|
||||
}
|
||||
else {
|
||||
// The file has no extension or the only '.' in the file is an initial '.', as in a hidden file.
|
||||
// Add the object id to the end of the file name.
|
||||
fileName += objectIdSuffix;
|
||||
}
|
||||
localFilePath.append(File.separator);
|
||||
localFilePath.append(fileName);
|
||||
|
||||
// If the local file doesn't already exist, create it now.
|
||||
// The existence check is necessary because it is possible to apply multiple tags with the same name to a file.
|
||||
File localFile = new File(localFilePath.toString());
|
||||
if (!localFile.exists()) {
|
||||
ExtractFscContentVisitor.extract(file, localFile, null, null);
|
||||
}
|
||||
|
||||
// Add the hyperlink to the row. A column header for it was created in startTable().
|
||||
StringBuilder localFileLink = new StringBuilder();
|
||||
localFileLink.append("<a href=\"file:///");
|
||||
localFileLink.append(localFilePath.toString());
|
||||
localFileLink.append("\">View File</a>");
|
||||
row.add(localFileLink.toString());
|
||||
|
||||
StringBuilder builder = new StringBuilder();
|
||||
builder.append("\t<tr>\n");
|
||||
@ -561,90 +580,6 @@ public class ReportHTML implements TableReportModule {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*
|
||||
* @param row The row.
|
||||
* @param sourceArtifact The artifact associated with the row.
|
||||
*/
|
||||
private void addRowDataForSourceArtifact(List<String> row, BlackboardArtifact sourceArtifact) {
|
||||
int artifactTypeID = sourceArtifact.getArtifactTypeID();
|
||||
BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID);
|
||||
switch (type) {
|
||||
case TSK_TAG_FILE:
|
||||
addRowDataForFileTagArtifact(row, sourceArtifact);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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.
|
||||
if (file.isDir() ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
|
||||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS) {
|
||||
row.add("");
|
||||
return;
|
||||
}
|
||||
|
||||
// Make a folder for the local file with the same name as the tag.
|
||||
StringBuilder localFilePath = new StringBuilder();
|
||||
localFilePath.append(path);
|
||||
HashSet<String> tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact);
|
||||
if (!tagNames.isEmpty()) {
|
||||
localFilePath.append(tagNames.iterator().next());
|
||||
}
|
||||
File localFileFolder = new File(localFilePath.toString());
|
||||
if (!localFileFolder.exists()) {
|
||||
localFileFolder.mkdirs();
|
||||
}
|
||||
|
||||
// Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness.
|
||||
String fileName = file.getName();
|
||||
String objectIdSuffix = "_" + sourceArtifact.getObjectID();
|
||||
int lastDotIndex = fileName.lastIndexOf(".");
|
||||
if (lastDotIndex != -1 && lastDotIndex != 0) {
|
||||
// The file name has a conventional extension. Insert the object id before the '.' of the extension.
|
||||
fileName = fileName.substring(0, lastDotIndex) + objectIdSuffix + fileName.substring(lastDotIndex, fileName.length());
|
||||
}
|
||||
else {
|
||||
// The file has no extension or the only '.' in the file is an initial '.', as in a hidden file.
|
||||
// Add the object id to the end of the file name.
|
||||
fileName += objectIdSuffix;
|
||||
}
|
||||
localFilePath.append(File.separator);
|
||||
localFilePath.append(fileName);
|
||||
|
||||
// If the local file doesn't already exist, create it now.
|
||||
// The existence check is necessary because it is possible to apply multiple tags with the same name to a file.
|
||||
File localFile = new File(localFilePath.toString());
|
||||
if (!localFile.exists()) {
|
||||
ExtractFscContentVisitor.extract(file, localFile, null, null);
|
||||
}
|
||||
|
||||
// Add the hyperlink to the row. A column header for it was created in startTable().
|
||||
StringBuilder localFileLink = new StringBuilder();
|
||||
localFileLink.append("<a href=\"file:///");
|
||||
localFileLink.append(localFilePath.toString());
|
||||
localFileLink.append("\">View File</a>");
|
||||
row.add(localFileLink.toString());
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex);
|
||||
row.add("");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return a String date for the long date given.
|
||||
* @param date date as a long
|
||||
@ -665,7 +600,7 @@ public class ReportHTML implements TableReportModule {
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return "HTML";
|
||||
return "Results - HTML";
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -704,11 +639,11 @@ public class ReportHTML implements TableReportModule {
|
||||
"table tr:nth-child(even) td {background: #f3f3f3;}";
|
||||
cssOut.write(css);
|
||||
} 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) {
|
||||
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) {
|
||||
logger.log(Level.SEVERE, "Error creating Writer for index.css.");
|
||||
logger.log(Level.SEVERE, "Error creating Writer for index.css.", ex);
|
||||
} finally {
|
||||
try {
|
||||
if(cssOut != null) {
|
||||
|
@ -23,37 +23,30 @@
|
||||
package org.sleuthkit.autopsy.report;
|
||||
|
||||
/**
|
||||
* Interface extended by TableReportModule and GeneralReportModule.
|
||||
* Contains vital report information to be used by every report.
|
||||
* Interface got report modules that plug in to the reporting infrastructure.
|
||||
*/
|
||||
public interface ReportModule {
|
||||
|
||||
/**
|
||||
* Returns a basic string name for the report. What is 'officially' titled.
|
||||
*
|
||||
* @return the report name
|
||||
* Get the name of the report this module generates.
|
||||
*/
|
||||
public String getName();
|
||||
|
||||
/**
|
||||
* Returns a one line user friendly description of the type of report this
|
||||
* module generates
|
||||
* @return user-friendly report description
|
||||
* Gets a one-line, user friendly description of the type of report this
|
||||
* module generates.
|
||||
*/
|
||||
public String getDescription();
|
||||
|
||||
/**
|
||||
* Returns the extension that is used for the report
|
||||
*
|
||||
* @return String the extension the file will be saved as
|
||||
*
|
||||
* Gets the extension of the report file, if any, generated by this module.
|
||||
* @return File name extension, may be null.
|
||||
*/
|
||||
public String getExtension();
|
||||
|
||||
/**
|
||||
* Returns the path to the main (or only) file for the report.
|
||||
*
|
||||
* @return String path to the report file
|
||||
* Gets the path of the report file, if any, generated by this module.
|
||||
* @return File path, may be null.
|
||||
*/
|
||||
public String getFilePath();
|
||||
}
|
@ -48,56 +48,61 @@ public class ReportProgressPanel extends javax.swing.JPanel {
|
||||
}
|
||||
|
||||
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.setMaximum(100);
|
||||
|
||||
reportLabel.setText(reportName);
|
||||
processingLabel.setText("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
|
||||
final String linkPath = reportPath;
|
||||
pathLabel.addMouseListener(new MouseListener() {
|
||||
final String linkPath = reportPath;
|
||||
pathLabel.addMouseListener(new MouseListener() {
|
||||
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void mouseClicked(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
}
|
||||
@Override
|
||||
public void mousePressed(MouseEvent e) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
File file = new File(linkPath);
|
||||
try {
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (IOException ex) {
|
||||
} catch (IllegalArgumentException ex) {
|
||||
@Override
|
||||
public void mouseReleased(MouseEvent e) {
|
||||
File file = new File(linkPath);
|
||||
try {
|
||||
// try to open the parent path if the file doens't exist
|
||||
Desktop.getDesktop().open(file.getParentFile());
|
||||
} catch (IOException ex1) {
|
||||
Desktop.getDesktop().open(file);
|
||||
} catch (IOException ex) {
|
||||
} catch (IllegalArgumentException ex) {
|
||||
try {
|
||||
// try to open the parent path if the file doens't exist
|
||||
Desktop.getDesktop().open(file.getParentFile());
|
||||
} catch (IOException ex1) {
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
pathLabel.setForeground(Color.DARK_GRAY);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
}
|
||||
@Override
|
||||
public void mouseEntered(MouseEvent e) {
|
||||
pathLabel.setForeground(Color.DARK_GRAY);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
pathLabel.setForeground(Color.BLACK);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
@Override
|
||||
public void mouseExited(MouseEvent e) {
|
||||
pathLabel.setForeground(Color.BLACK);
|
||||
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
|
||||
}
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
else {
|
||||
pathLabel.setText("<html><u>No report file</u></html>");
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
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