Merge remote-tracking branch 'upstream/develop' into hashdb_sqlite

This commit is contained in:
Samuel H. Kenyon 2013-11-20 14:47:33 -05:00
commit a939f04b72
214 changed files with 15016 additions and 13170 deletions

14
.gitattributes vendored Normal file
View 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

BIN
0

Binary file not shown.

View File

@ -2,5 +2,8 @@ Changes to make to API when we are ready to make backward incompatible changes:
- HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API. - HTMLReport has special API for more context on columns and special handling in REportGenerator. Change all reports to the new API.
- DataContentViewer.isPreferred does not need isSupported to be passed in - DataContentViewer.isPreferred does not need isSupported to be passed in
- DataContentViewerHex and STrings can have the public setDataView methods removed in favor of the new private ones - DataContentViewerHex and Strings can have the public setDataView methods removed in favor of the new private ones
Content.getUniquePath() shoudl not thrown TskException. We should deal with it in the method. - Content.getUniquePath() should not thrown TskException. We should deal with it in the method.
- Make the list of events that Case fires off to be part of an enum to group them together (like IngestManager does).
- Sub-modules in RecentActivity have a bunch of public/protected variables that do not need to be. (i.e. ExtractRegistry.rrFullFound).
- Delete BrowserType enum and BrowserActivityType in RecentActivity.

View File

@ -11,8 +11,7 @@ correct C libraries.
STEPS: STEPS:
1) Get Java Setup 1) Get Java Setup
1a) Download and install 32-bit version of JDK version 1.7 (32-bit is currently 1a) Download and install JDK version 1.7. You can now use 32-bit or 64-bit, but special work is needed to get The Sleuth Kit to compile as 64-bit. So, 32-bit is easier.
needed even if you have a 64-bit system).
Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support Autopsy has been used and tested with Oracle JavaSE and the included JavaFX support
(http://www.oracle.com/technetwork/java/javase/downloads/index.html). (http://www.oracle.com/technetwork/java/javase/downloads/index.html).
@ -26,7 +25,8 @@ Note: Netbeans IDE is not required to build and run Autopsy,
but it is a recommended IDE to use for development of Autopsy modules. but it is a recommended IDE to use for development of Autopsy modules.
1d) (optional) If you are going to package Autopsy, then you'll also 1d) (optional) If you are going to package Autopsy, then you'll also
need to set JRE_HOME to the root JRE directory. need to set JRE_HOME_32 to the root 32-bit JRE directory and/or JRE_HOME_64
to the root 64-bit JRE directory.
1e) (optional) For some Autopsy features to be functional, you need to add java executable to the system PATH. 1e) (optional) For some Autopsy features to be functional, you need to add java executable to the system PATH.
@ -37,6 +37,9 @@ need to set JRE_HOME to the root JRE directory.
later). All you need is the dll file. Note that you will get a later). All you need is the dll file. Note that you will get a
launching error if you use libewf 1. launching error if you use libewf 1.
- http://sourceforge.net/projects/libewf/ - http://sourceforge.net/projects/libewf/
If you want to build the 64-bit version of The Sleuth Kit, download
our 64-bit version of libewf:
- https://github.com/sleuthkit/libewf_64bit
2b) Set LIBEWF_HOME environment variable to root directory of LIBEWF 2b) Set LIBEWF_HOME environment variable to root directory of LIBEWF
@ -97,13 +100,13 @@ BACKGROUND:
Here are some notes to shed some light on what is going on during Here are some notes to shed some light on what is going on during
the build process. the build process.
- NetBeans uses ant to build Autopsy. The build target locates TSK - The Sleuth Kit Java datamodel JAR file has native libraries
(and LIBEWF) based on the environment variables and copies the that are copied into it.
needed JAR and library files into the DataModel module in the Autopsy
project (see build-unix.xml and build-windows.xml in the root - NetBeans uses ant to build Autopsy. The build target copies the
directory for details). If you want to use the debug version of TSK datamodel JAR file into the project. If you want to use the
the TSK dll, then edit the copy line in the build-windows.xml file debug version of the TSK dll, then there is a different ant target
to copy from the Debug folder. in TSK to copy the debug versions of the dlls.
- On a Windows system, the ant target copies all needed libraries - On a Windows system, the ant target copies all needed libraries
to the autopsy folder. On a Unix system, the ant taget copies only to the autopsy folder. On a Unix system, the ant taget copies only

View File

@ -191,6 +191,7 @@
</dependency> </dependency>
</module-dependencies> </module-dependencies>
<public-packages> <public-packages>
<package>org.sleuthkit.autopsy.actions</package>
<package>org.sleuthkit.autopsy.casemodule</package> <package>org.sleuthkit.autopsy.casemodule</package>
<package>org.sleuthkit.autopsy.casemodule.services</package> <package>org.sleuthkit.autopsy.casemodule.services</package>
<package>org.sleuthkit.autopsy.core</package> <package>org.sleuthkit.autopsy.core</package>

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

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

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

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

View File

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

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

View File

@ -78,7 +78,7 @@
<Component class="javax.swing.JButton" name="okButton"> <Component class="javax.swing.JButton" name="okButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
@ -91,7 +91,7 @@
<Component class="javax.swing.JButton" name="cancelButton"> <Component class="javax.swing.JButton" name="cancelButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
@ -104,7 +104,7 @@
<StringArray count="0"/> <StringArray count="0"/>
</Property> </Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagCombo.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<AuxValues> <AuxValues>
@ -114,31 +114,31 @@
<Component class="javax.swing.JLabel" name="tagLabel"> <Component class="javax.swing.JLabel" name="tagLabel">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.tagLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JLabel" name="commentLabel"> <Component class="javax.swing.JLabel" name="commentLabel">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JTextField" name="commentText"> <Component class="javax.swing.JTextField" name="commentText">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
<Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="toolTipText" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.commentText.toolTipText" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JButton" name="newTagButton"> <Component class="javax.swing.JButton" name="newTagButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="TagAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameAndCommentDialog.newTagButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>

View File

@ -16,11 +16,13 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.directorytree; package org.sleuthkit.autopsy.actions;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.TreeSet; import java.util.HashMap;
import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.ActionMap; import javax.swing.ActionMap;
import javax.swing.InputMap; import javax.swing.InputMap;
@ -29,28 +31,28 @@ import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.KeyStroke; import javax.swing.KeyStroke;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.datamodel.Tags; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
/** public class GetTagNameAndCommentDialog extends JDialog {
* Tag dialog for tagging files and results. User enters an optional comment. private static final String NO_TAG_NAMES_MESSAGE = "No Tags";
*/ private final HashMap<String, TagName> tagNames = new HashMap<>();
public class TagAndCommentDialog extends JDialog { private TagNameAndComment tagNameAndComment = null;
private static final String NO_TAG_MESSAGE = "No Tags"; public static class TagNameAndComment {
private String tagName = ""; private TagName tagName;
private String comment = "";
public static class CommentedTag {
private String name;
private String comment; private String comment;
CommentedTag(String name, String comment) { private TagNameAndComment(TagName tagName, String comment) {
this.name = name; this.tagName = tagName;
this.comment = comment; this.comment = comment;
} }
public String getName() { public TagName getTagName() {
return name; return tagName;
} }
public String getComment() { public String getComment() {
@ -58,25 +60,16 @@ public class TagAndCommentDialog extends JDialog {
} }
} }
public static CommentedTag doDialog() { public static TagNameAndComment doDialog() {
TagAndCommentDialog dialog = new TagAndCommentDialog(); GetTagNameAndCommentDialog dialog = new GetTagNameAndCommentDialog();
if (!dialog.tagName.isEmpty()) { return dialog.tagNameAndComment;
return new CommentedTag(dialog.tagName, dialog.comment);
}
else {
return null;
}
} }
/** private GetTagNameAndCommentDialog() {
* Creates new form TagDialog super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
*/
private TagAndCommentDialog() {
super((JFrame)WindowManager.getDefault().getMainWindow(), "Tag and Comment", true);
initComponents(); initComponents();
// Close the dialog when Esc is pressed // Set up the dialog to close when Esc is pressed.
String cancelName = "cancel"; String cancelName = "cancel";
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT); InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName); inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
@ -88,23 +81,29 @@ public class TagAndCommentDialog extends JDialog {
} }
}); });
// get the current list of tag names // Populate the combo box with the available tag names and save the
TreeSet<String> tags = Tags.getAllTagNames(); // tag name DTOs to be enable to return the one the user selects.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
// if there are no tags, add the NO_TAG_MESSAGE List<TagName> currentTagNames = null;
if (tags.isEmpty()) { try {
tags.add(NO_TAG_MESSAGE); currentTagNames = tagsManager.getAllTagNames();
}
catch (TskCoreException ex) {
Logger.getLogger(GetTagNameAndCommentDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
if (null != currentTagNames && currentTagNames.isEmpty()) {
tagCombo.addItem(NO_TAG_NAMES_MESSAGE);
}
else {
for (TagName tagName : currentTagNames) {
tagNames.put(tagName.getDisplayName(), tagName);
tagCombo.addItem(tagName.getDisplayName());
}
} }
// add the tags to the combo box // Center and show the dialog box.
for (String tag : tags) {
tagCombo.addItem(tag);
}
//center it
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow()); this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
setVisible(true);
setVisible(true); // blocks
} }
/** /**
@ -130,30 +129,30 @@ public class TagAndCommentDialog extends JDialog {
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.okButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() { okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt); okButtonActionPerformed(evt);
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.cancelButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() { cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt); cancelButtonActionPerformed(evt);
} }
}); });
tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagCombo.toolTipText")); // NOI18N tagCombo.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagCombo.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.tagLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(tagLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.tagLabel.text")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(commentLabel, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentLabel.text")); // NOI18N
commentText.setText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.text")); // NOI18N commentText.setText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.text")); // NOI18N
commentText.setToolTipText(org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.commentText.toolTipText")); // NOI18N commentText.setToolTipText(org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.commentText.toolTipText")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(TagAndCommentDialog.class, "TagAndCommentDialog.newTagButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(newTagButton, org.openide.util.NbBundle.getMessage(GetTagNameAndCommentDialog.class, "GetTagNameAndCommentDialog.newTagButton.text")); // NOI18N
newTagButton.addActionListener(new java.awt.event.ActionListener() { newTagButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
newTagButtonActionPerformed(evt); newTagButtonActionPerformed(evt);
@ -212,27 +211,26 @@ public class TagAndCommentDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
tagName = (String)tagCombo.getSelectedItem(); tagNameAndComment = new TagNameAndComment(tagNames.get((String)tagCombo.getSelectedItem()), commentText.getText());
comment = commentText.getText();
dispose(); dispose();
}//GEN-LAST:event_okButtonActionPerformed }//GEN-LAST:event_okButtonActionPerformed
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
tagNameAndComment = null;
dispose(); dispose();
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
/**
* Closes the dialog
*/
private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog private void closeDialog(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_closeDialog
tagNameAndComment = null;
dispose(); dispose();
}//GEN-LAST:event_closeDialog }//GEN-LAST:event_closeDialog
private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed private void newTagButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_newTagButtonActionPerformed
String newTagName = CreateTagDialog.getNewTagNameDialog(null); TagName newTagName = GetTagNameDialog.doDialog();
if (newTagName != null) { if (newTagName != null) {
tagCombo.addItem(newTagName); tagNames.put(newTagName.getDisplayName(), newTagName);
tagCombo.setSelectedItem(newTagName); tagCombo.addItem(newTagName.getDisplayName());
tagCombo.setSelectedItem(newTagName.getDisplayName());
} }
}//GEN-LAST:event_newTagButtonActionPerformed }//GEN-LAST:event_newTagButtonActionPerformed

View File

@ -72,7 +72,7 @@
<Component class="javax.swing.JButton" name="cancelButton"> <Component class="javax.swing.JButton" name="cancelButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.cancelButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
@ -82,7 +82,7 @@
<Component class="javax.swing.JButton" name="okButton"> <Component class="javax.swing.JButton" name="okButton">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.okButton.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>
@ -124,7 +124,7 @@
<Component class="javax.swing.JLabel" name="preexistingLabel"> <Component class="javax.swing.JLabel" name="preexistingLabel">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.preexistingLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
@ -133,7 +133,7 @@
<Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor"> <Property name="border" type="javax.swing.border.Border" editor="org.netbeans.modules.form.editors2.BorderEditor">
<Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo"> <Border info="org.netbeans.modules.form.compat2.border.TitledBorderInfo">
<TitledBorder title="New Tag"> <TitledBorder title="New Tag">
<ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString PropertyName="titleX" bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.newTagPanel.border.title" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</TitledBorder> </TitledBorder>
</Border> </Border>
</Property> </Property>
@ -168,14 +168,14 @@
<Component class="javax.swing.JLabel" name="tagNameLabel"> <Component class="javax.swing.JLabel" name="tagNameLabel">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameLabel.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
</Component> </Component>
<Component class="javax.swing.JTextField" name="tagNameField"> <Component class="javax.swing.JTextField" name="tagNameField">
<Properties> <Properties>
<Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor"> <Property name="text" type="java.lang.String" editor="org.netbeans.modules.i18n.form.FormI18nStringEditor">
<ResourceString bundle="org/sleuthkit/autopsy/directorytree/Bundle.properties" key="CreateTagDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/actions/Bundle.properties" key="GetTagNameDialog.tagNameField.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events> <Events>

View File

@ -16,72 +16,130 @@
* See the License for the specific language governing permissions and * See the License for the specific language governing permissions and
* limitations under the License. * limitations under the License.
*/ */
package org.sleuthkit.autopsy.directorytree; package org.sleuthkit.autopsy.actions;
import java.awt.Dimension; import java.awt.event.ActionEvent;
import java.awt.Toolkit;
import java.awt.event.KeyEvent; import java.awt.event.KeyEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.logging.Level;
import javax.swing.AbstractAction;
import javax.swing.ActionMap;
import javax.swing.InputMap;
import javax.swing.JComponent;
import javax.swing.JDialog; import javax.swing.JDialog;
import javax.swing.JFrame; import javax.swing.JFrame;
import javax.swing.JOptionPane; import javax.swing.JOptionPane;
import javax.swing.KeyStroke;
import javax.swing.table.AbstractTableModel; import javax.swing.table.AbstractTableModel;
import org.openide.util.ImageUtilities; import org.openide.util.ImageUtilities;
import org.sleuthkit.autopsy.datamodel.Tags; import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.services.TagsManager;
import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.TagName;
import org.sleuthkit.datamodel.TskCoreException;
public class CreateTagDialog extends JDialog { public class GetTagNameDialog extends JDialog {
private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png"; private static final String TAG_ICON_PATH = "org/sleuthkit/autopsy/images/tag-folder-blue-icon-16.png";
private static String newTagName; private final HashMap<String, TagName> tagNames = new HashMap<>();
private TagName tagName = null;
/** public static TagName doDialog() {
* Creates new form CreateTagDialog GetTagNameDialog dialog = new GetTagNameDialog();
*/ return dialog.tagName;
private CreateTagDialog(JFrame parent) {
super(parent, true);
init();
} }
public static String getNewTagNameDialog(JFrame parent) { private GetTagNameDialog() {
new CreateTagDialog(parent); super((JFrame)WindowManager.getDefault().getMainWindow(), "Create Tag", true);
return newTagName; setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH));
}
private void init() {
setTitle("Create a new tag");
initComponents(); initComponents();
tagsTable.setModel(new TagsTableModel()); // Set up the dialog to close when Esc is pressed.
tagsTable.setTableHeader(null); String cancelName = "cancel";
InputMap inputMap = getRootPane().getInputMap(JComponent.WHEN_ANCESTOR_OF_FOCUSED_COMPONENT);
inputMap.put(KeyStroke.getKeyStroke(KeyEvent.VK_ESCAPE, 0), cancelName);
ActionMap actionMap = getRootPane().getActionMap();
actionMap.put(cancelName, new AbstractAction() {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
});
//completely disable selections // Get the current set of tag names and hash them for a speedy lookup in
// case the user chooses an existing tag name from the tag names table.
TagsManager tagsManager = Case.getCurrentCase().getServices().getTagsManager();
List<TagName> currentTagNames = null;
try {
currentTagNames = tagsManager.getAllTagNames();
}
catch (TskCoreException ex) {
Logger.getLogger(GetTagNameDialog.class.getName()).log(Level.SEVERE, "Failed to get tag names", ex);
}
if (null != currentTagNames) {
for (TagName name : currentTagNames) {
this.tagNames.put(name.getDisplayName(), name);
}
}
else {
currentTagNames = new ArrayList<>();
}
// Populate the tag names table.
tagsTable.setModel(new TagsTableModel(currentTagNames));
tagsTable.setTableHeader(null);
tagsTable.setCellSelectionEnabled(false); tagsTable.setCellSelectionEnabled(false);
tagsTable.setFocusable(false); tagsTable.setFocusable(false);
tagsTable.setRowHeight(tagsTable.getRowHeight() + 5); tagsTable.setRowHeight(tagsTable.getRowHeight() + 5);
setIconImage(ImageUtilities.loadImage(TAG_ICON_PATH)); // Center and show the dialog box.
this.setLocationRelativeTo(WindowManager.getDefault().getMainWindow());
Dimension screenDimension = Toolkit.getDefaultToolkit().getScreenSize(); setVisible(true);
// set the popUp window / JFrame
int w = this.getSize().width;
int h = this.getSize().height;
// set the location of the popUp Window on the center of the screen
setLocation((screenDimension.width - w) / 2, (screenDimension.height - h) / 2);
setVisible(true); //blocks
} }
private boolean containsIllegalCharacters(String content) { private boolean containsIllegalCharacters(String content) {
if ((content.contains("\\") || content.contains(":") || content.contains("*") return (content.contains("\\")||
|| content.contains("?") || content.contains("\"") || content.contains("<") content.contains(":") ||
|| content.contains(">") || content.contains("|"))) { content.contains("*") ||
return true; content.contains("?") ||
content.contains("\"")||
content.contains("<") ||
content.contains(">") ||
content.contains("|"));
} }
private class TagsTableModel extends AbstractTableModel {
private final ArrayList<TagName> tagNames = new ArrayList<>();
TagsTableModel(List<TagName> tagNames) {
for (TagName tagName : tagNames) {
this.tagNames.add(tagName);
}
}
@Override
public int getRowCount() {
return tagNames.size();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false; return false;
} }
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getValueAt(int rowIndex, int columnIndex) {
return tagNames.get(rowIndex).getDisplayName();
}
}
/** /**
* This method is called from within the constructor to initialize the form. * This method is called from within the constructor to initialize the form.
* WARNING: Do NOT modify this code. The content of this method is always * WARNING: Do NOT modify this code. The content of this method is always
@ -107,14 +165,14 @@ public class CreateTagDialog extends JDialog {
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.cancelButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(cancelButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.cancelButton.text")); // NOI18N
cancelButton.addActionListener(new java.awt.event.ActionListener() { cancelButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
cancelButtonActionPerformed(evt); cancelButtonActionPerformed(evt);
} }
}); });
org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.okButton.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(okButton, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.okButton.text")); // NOI18N
okButton.addActionListener(new java.awt.event.ActionListener() { okButton.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) { public void actionPerformed(java.awt.event.ActionEvent evt) {
okButtonActionPerformed(evt); okButtonActionPerformed(evt);
@ -137,13 +195,13 @@ public class CreateTagDialog extends JDialog {
tagsTable.setTableHeader(null); tagsTable.setTableHeader(null);
jScrollPane1.setViewportView(tagsTable); jScrollPane1.setViewportView(tagsTable);
org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.preexistingLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(preexistingLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.preexistingLabel.text")); // NOI18N
newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.newTagPanel.border.title"))); // NOI18N newTagPanel.setBorder(javax.swing.BorderFactory.createTitledBorder(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.newTagPanel.border.title"))); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameLabel.text")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(tagNameLabel, org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameLabel.text")); // NOI18N
tagNameField.setText(org.openide.util.NbBundle.getMessage(CreateTagDialog.class, "CreateTagDialog.tagNameField.text")); // NOI18N tagNameField.setText(org.openide.util.NbBundle.getMessage(GetTagNameDialog.class, "GetTagNameDialog.tagNameField.text")); // NOI18N
tagNameField.addKeyListener(new java.awt.event.KeyAdapter() { tagNameField.addKeyListener(new java.awt.event.KeyAdapter() {
public void keyReleased(java.awt.event.KeyEvent evt) { public void keyReleased(java.awt.event.KeyEvent evt) {
tagNameFieldKeyReleased(evt); tagNameFieldKeyReleased(evt);
@ -211,21 +269,40 @@ public class CreateTagDialog extends JDialog {
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed private void cancelButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelButtonActionPerformed
newTagName = null; tagName = null;
dispose(); dispose();
}//GEN-LAST:event_cancelButtonActionPerformed }//GEN-LAST:event_cancelButtonActionPerformed
private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed private void okButtonActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_okButtonActionPerformed
String tagName = tagNameField.getText(); String tagDisplayName = tagNameField.getText();
if (tagName.isEmpty()) { if (tagDisplayName.isEmpty()) {
JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, "Must supply a tag name to continue.", "Tag Name", JOptionPane.ERROR_MESSAGE);
} else if (containsIllegalCharacters(tagName)) { }
JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", else if (containsIllegalCharacters(tagDisplayName)) {
"Illegal Characters", JOptionPane.ERROR_MESSAGE); JOptionPane.showMessageDialog(null, "The tag name contains illegal characters.\nCannot contain any of the following symbols: \\ : * ? \" < > |", "Illegal Characters", JOptionPane.ERROR_MESSAGE);
} else { }
newTagName = tagName; else {
tagName = tagNames.get(tagDisplayName);
if (tagName == null) {
try {
tagName = Case.getCurrentCase().getServices().getTagsManager().addTagName(tagDisplayName);
dispose(); dispose();
} }
catch (TskCoreException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
JOptionPane.showMessageDialog(null, "Unable to add the " + tagDisplayName + " tag name to the case.", "Tagging Error", JOptionPane.ERROR_MESSAGE);
tagName = null;
}
catch (TagsManager.TagNameAlreadyExistsException ex) {
Logger.getLogger(AddTagAction.class.getName()).log(Level.SEVERE, "Error adding " + tagDisplayName + " tag name", ex);
JOptionPane.showMessageDialog(null, "A " + tagDisplayName + " tag name has already been defined.", "Duplicate Tag Error", JOptionPane.ERROR_MESSAGE);
tagName = null;
}
}
else {
dispose();
}
}
}//GEN-LAST:event_okButtonActionPerformed }//GEN-LAST:event_okButtonActionPerformed
private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased private void formKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_formKeyReleased
@ -251,32 +328,5 @@ public class CreateTagDialog extends JDialog {
private javax.swing.JTable tagsTable; private javax.swing.JTable tagsTable;
// End of variables declaration//GEN-END:variables // End of variables declaration//GEN-END:variables
private class TagsTableModel extends AbstractTableModel {
List<String> tagNames;
TagsTableModel() {
tagNames = new ArrayList<>(Tags.getAllTagNames());
}
@Override
public int getRowCount() {
return tagNames.size();
}
@Override
public boolean isCellEditable(int rowIndex, int columnIndex) {
return false;
}
@Override
public int getColumnCount() {
return 1;
}
@Override
public String getValueAt(int rowIndex, int columnIndex) {
return tagNames.get(rowIndex);
}
}
} }

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

View File

@ -109,6 +109,71 @@ public class Case implements SleuthkitCase.ErrorObserver {
// pcs is initialized in CaseListener constructor // pcs is initialized in CaseListener constructor
private static final PropertyChangeSupport pcs = new PropertyChangeSupport(Case.class); private static final PropertyChangeSupport pcs = new PropertyChangeSupport(Case.class);
/**
* Events that the case module will fire. Event listeners can get the event
* name by using String returned by toString() method on a specific event.
*/
/* @@@ BC: I added this as a place holder for what I want this to be, but
* this is not the time to change it. We'll start using this at a major release
* version.
*/
private enum CaseModuleEvent_DoNotUse {
/**
* Property name that indicates the name of the current case has changed.
* Fired with the case is renamed, and when the current case is
* opened/closed/changed. The value is a String: the name of the case. The
* empty string ("") is used for no open case.
*/
// @@@ BC: I propose that this is no longer called for case open/close.
CASE_NAME("caseName"),
/**
* Property name that indicates the number of the current case has changed.
* Fired with the case number is changed. The value is an int: the number of
* the case. -1 is used for no case number set.
*/
CASE_NUMBER("caseNumber"),
/**
* Property name that indicates the examiner of the current case has
* changed. Fired with the case examiner is changed. The value is a String:
* the name of the examiner. The empty string ("") is used for no examiner
* set.
*/
CASE_EXAMINER("caseExaminer"),
/**
* Property name that indicates a new data source (image, disk or local
* file) has been added to the current case. The new value is the
* newly-added instance of the new data source, and the old value is always
* null.
*/
CASE_ADD_DATA_SOURCE("addDataSource"),
/**
* Property name that indicates a data source has been removed from the
* current case. The "old value" is the (int) content ID of the data source
* that was removed, the new value is the instance of the data source.
*/
CASE_DEL_DATA_SOURCE("removeDataSource"),
/**
* Property name that indicates the currently open case has changed. The new
* value is the instance of the opened Case, or null if there is no open
* case. The old value is the instance of the closed Case, or null if there
* was no open case.
*/
CASE_CURRENT_CASE("currentCase");
private String name;
CaseModuleEvent_DoNotUse(String name) {
this.name = name;
}
public String getName() {
return this.name;
}
};
private String name; private String name;

View File

@ -30,7 +30,7 @@
</Group> </Group>
<Group type="102" alignment="0" attributes="0"> <Group type="102" alignment="0" attributes="0">
<Component id="caseNameLabel" min="-2" max="-2" attributes="0"/> <Component id="caseNameLabel" min="-2" max="-2" attributes="0"/>
<EmptySpace min="-2" pref="26" max="-2" attributes="0"/> <EmptySpace max="32767" attributes="0"/>
<Component id="caseNameTextField" min="-2" pref="296" max="-2" attributes="0"/> <Component id="caseNameTextField" min="-2" pref="296" max="-2" attributes="0"/>
</Group> </Group>
<Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/> <Component id="caseDirTextField" alignment="0" min="-2" pref="380" max="-2" attributes="1"/>
@ -51,7 +51,7 @@
<EmptySpace type="separate" max="-2" attributes="0"/> <EmptySpace type="separate" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">
<Component id="caseNameLabel" alignment="3" min="-2" max="-2" attributes="0"/> <Component id="caseNameLabel" alignment="3" min="-2" max="-2" attributes="0"/>
<Component id="caseNameTextField" alignment="3" min="-2" pref="20" max="-2" attributes="0"/> <Component id="caseNameTextField" alignment="3" min="-2" max="-2" attributes="0"/>
</Group> </Group>
<EmptySpace type="unrelated" max="-2" attributes="0"/> <EmptySpace type="unrelated" max="-2" attributes="0"/>
<Group type="103" groupAlignment="3" attributes="0"> <Group type="103" groupAlignment="3" attributes="0">

View File

@ -93,7 +93,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
jLabel2 = new javax.swing.JLabel(); jLabel2 = new javax.swing.JLabel();
caseDirTextField = new javax.swing.JTextField(); caseDirTextField = new javax.swing.JTextField();
jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); jLabel1.setFont(new java.awt.Font("Tahoma", 1, 14)); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(jLabel1, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.jLabel1.text_1")); // NOI18N
org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N org.openide.awt.Mnemonics.setLocalizedText(caseNameLabel, org.openide.util.NbBundle.getMessage(NewCaseVisualPanel1.class, "NewCaseVisualPanel1.caseNameLabel.text_1")); // NOI18N
@ -133,7 +133,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
.addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(caseParentDirTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
.addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup() .addGroup(javax.swing.GroupLayout.Alignment.LEADING, layout.createSequentialGroup()
.addComponent(caseNameLabel) .addComponent(caseNameLabel)
.addGap(26, 26, 26) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 296, javax.swing.GroupLayout.PREFERRED_SIZE))
.addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(caseDirTextField, javax.swing.GroupLayout.Alignment.LEADING, javax.swing.GroupLayout.PREFERRED_SIZE, 380, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
@ -148,7 +148,7 @@ final class NewCaseVisualPanel1 extends JPanel implements DocumentListener{
.addGap(18, 18, 18) .addGap(18, 18, 18)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(caseNameLabel) .addComponent(caseNameLabel)
.addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, 20, javax.swing.GroupLayout.PREFERRED_SIZE)) .addComponent(caseNameTextField, javax.swing.GroupLayout.PREFERRED_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.PREFERRED_SIZE))
.addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED) .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.UNRELATED)
.addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE) .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.BASELINE)
.addComponent(caseDirLabel) .addComponent(caseDirLabel)

View File

@ -2,7 +2,7 @@
* *
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2012 Basis Technology Corp. * Copyright 2012-2013 Basis Technology Corp.
* *
* Copyright 2012 42six Solutions. * Copyright 2012 42six Solutions.
* Contact: aebadirad <at> 42six <dot> com * Contact: aebadirad <at> 42six <dot> com
@ -37,22 +37,30 @@ public class Services implements Closeable {
// NOTE: all new services added to Services class must be added to this list // NOTE: all new services added to Services class must be added to this list
// of services. // of services.
private List<Closeable> services = new ArrayList<Closeable>(); private List<Closeable> services = new ArrayList<>();
// services // services
private FileManager fileManager; private FileManager fileManager;
private TagsManager tagsManager;
public Services(SleuthkitCase tskCase) { public Services(SleuthkitCase tskCase) {
this.tskCase = tskCase; this.tskCase = tskCase;
//create and initialize FileManager as early as possibly in the new/opened Case //create and initialize FileManager as early as possibly in the new/opened Case
fileManager = new FileManager(tskCase); fileManager = new FileManager(tskCase);
services.add(fileManager); services.add(fileManager);
tagsManager = new TagsManager(tskCase);
services.add(tagsManager);
} }
public FileManager getFileManager() { public FileManager getFileManager() {
return fileManager; return fileManager;
} }
public TagsManager getTagsManager() {
return tagsManager;
}
@Override @Override
public void close() throws IOException { public void close() throws IOException {
// close all services // close all services

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

View File

@ -310,6 +310,11 @@
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.ReportBodyFile.getDefault"/> <attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.ReportBodyFile.getDefault"/>
<attr name="position" intvalue="902"/> <attr name="position" intvalue="902"/>
</file> </file>
<file name="org-sleuthkit-autopsy-report-FileReportText.instance">
<attr name="instanceOf" stringvalue="org.sleuthkit.autopsy.report.FileReportModule"/>
<attr name="instanceCreate" methodvalue="org.sleuthkit.autopsy.report.FileReportText.getDefault"/>
<attr name="position" intvalue="903"/>
</file>
<!--<folder name="JavaHelp"> <!--<folder name="JavaHelp">
<file name="casemodule-helpset.xml" url="casemodule-helpset.xml"> <file name="casemodule-helpset.xml" url="casemodule-helpset.xml">
<attr name="position" intvalue="3075"/> <attr name="position" intvalue="3075"/>
@ -368,7 +373,7 @@
<attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance"/> <attr name="originalFile" stringvalue="Actions/Tools/org-sleuthkit-autopsy-ingest-IngestMessagesAction.instance"/>
</file> </file>
</folder> </folder>
<folder name="QuickSearch_hidden" /> <folder name="QuickSearch_hidden"/>
</folder> </folder>

View File

@ -257,20 +257,16 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
outputViewPane.setText(""); outputViewPane.setText("");
prevPageButton.setEnabled(false); prevPageButton.setEnabled(false);
nextPageButton.setEnabled(false); nextPageButton.setEnabled(false);
currentNode = null;
} }
@Override @Override
public void setNode(Node selectedNode) { public void setNode(Node selectedNode) {
// @@@ Remove this when the redundant setNode() calls problem is fixed.
if (currentNode == selectedNode) { if (currentNode == selectedNode) {
return; return;
} }
currentNode = selectedNode; currentNode = selectedNode;
// @@@ resetComponent() is currently a no-op due to the redundant setNode() calls problem.
// For now, do the reset here. Remove this when the redundant setNode() calls problem is fixed.
resetComponents();
// Make sure there is a node. Null might be passed to reset the viewer. // Make sure there is a node. Null might be passed to reset the viewer.
if (selectedNode == null) { if (selectedNode == null) {
return; return;
@ -308,8 +304,7 @@ public class DataContentViewerArtifact extends javax.swing.JPanel implements Dat
@Override @Override
public void resetComponent() { public void resetComponent() {
// @@@ Restore this when the redundant setNode() calls problem is fixed. resetComponents();
// resetComponents();
} }
@Override @Override

View File

@ -185,6 +185,7 @@ public class DataContentViewerMedia extends javax.swing.JPanel implements DataCo
@Override @Override
public void resetComponent() { public void resetComponent() {
videoPanel.reset(); videoPanel.reset();
imagePanel.reset();
lastFile = null; lastFile = null;
} }

View File

@ -607,9 +607,11 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
* Set number of matches to be displayed in the top right * Set number of matches to be displayed in the top right
* @param numMatches * @param numMatches
*/ */
public void setNumMatches(int numMatches) { public void setNumMatches(Integer numMatches) {
if (this.numberMatchLabel != null) {
this.numberMatchLabel.setText(Integer.toString(numMatches)); this.numberMatchLabel.setText(Integer.toString(numMatches));
} }
}
private class DummyNodeListener implements NodeListener { private class DummyNodeListener implements NodeListener {
private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait..."; private static final String DUMMY_NODE_DISPLAY_NAME = "Please Wait...";
@ -625,6 +627,7 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
if (load && containsReal(delta)) { if (load && containsReal(delta)) {
load = false; load = false;
setupTabs(nme.getNode()); setupTabs(nme.getNode());
updateMatches();
} }
} }
@ -637,8 +640,24 @@ public class DataResultPanel extends javax.swing.JPanel implements DataResult, C
return false; return false;
} }
/**
* Updates the Number of Matches label on the DataResultPanel.
*
*/
private void updateMatches() {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
if (rootNode != null && rootNode.getChildren() != null) {
setNumMatches(rootNode.getChildren().getNodesCount());
}
}
});
}
@Override @Override
public void childrenRemoved(NodeMemberEvent nme) { public void childrenRemoved(NodeMemberEvent nme) {
updateMatches();
} }
@Override @Override

View File

@ -293,6 +293,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel); final OutlineView ov = ((OutlineView) DataResultViewerTable.this.tableScrollPanel);
if (ov == null) {
return;
}
propertiesAcc.clear(); propertiesAcc.clear();
DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100); DataResultViewerTable.this.getAllChildPropertyHeadersRec(root, 100);
@ -339,7 +343,10 @@ public class DataResultViewerTable extends AbstractDataResultViewer {
//int scrollWidth = ttv.getWidth(); //int scrollWidth = ttv.getWidth();
int margin = 4; int margin = 4;
int startColumn = 1; int startColumn = 1;
ov.getOutline().setAutoResizeMode(JTable.AUTO_RESIZE_OFF);
// If there is only one column (which was removed from props above)
// Just let the table resize itself.
ov.getOutline().setAutoResizeMode((props.size() > 0) ? JTable.AUTO_RESIZE_OFF : JTable.AUTO_RESIZE_ALL_COLUMNS);

View File

@ -404,6 +404,7 @@ public class FXVideoPanel extends MediaViewVideoPanel {
*/ */
public void reset() { public void reset() {
if (mediaPlayer != null) { if (mediaPlayer != null) {
setInfoLabelText("");
if (mediaPlayer.getStatus() == Status.PLAYING) { if (mediaPlayer.getStatus() == Status.PLAYING) {
mediaPlayer.stop(); mediaPlayer.stop();
} }

View File

@ -105,11 +105,7 @@ public class Installer extends ModuleInstall {
} }
final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI", final String[] UI_MENU_ITEM_KEYS = new String[]{"MenuBarUI",
"MenuUI", };
"MenuItemUI",
"CheckBoxMenuItemUI",
"RadioButtonMenuItemUI",
"PopupMenuUI"};
Map<Object, Object> uiEntries = new TreeMap<Object, Object>(); Map<Object, Object> uiEntries = new TreeMap<Object, Object>();

View File

@ -106,6 +106,15 @@ public class MediaViewImagePanel extends javax.swing.JPanel {
} }
public void reset() {
Platform.runLater(new Runnable() {
@Override
public void run() {
fxImageView.setImage(null);
}
});
}
/** /**
* Show image * Show image
* *

View File

@ -39,12 +39,6 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
// 32 bit architectures // 32 bit architectures
private static final String[] ARCH32 = new String[]{"x86"}; private static final String[] ARCH32 = new String[]{"x86"};
// A Gstreamer implementation of MediaViewVideoPanel
private static GstVideoPanel gstVideoPanel = null;
// A JavaFX implmentation of MediaViewVideoPanel
private static FXVideoPanel fxVideoPanel = null;
/** /**
* Factory Method to create a MediaViewVideoPanel. * Factory Method to create a MediaViewVideoPanel.
* *
@ -78,10 +72,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
* @return a GstVideoPanel * @return a GstVideoPanel
*/ */
private static MediaViewVideoPanel getGstImpl() { private static MediaViewVideoPanel getGstImpl() {
if (gstVideoPanel == null) { return new GstVideoPanel();
gstVideoPanel = new GstVideoPanel();
}
return gstVideoPanel;
} }
/** /**
@ -90,10 +81,7 @@ public abstract class MediaViewVideoPanel extends JPanel implements FrameCapture
* @return a FXVideoPanel * @return a FXVideoPanel
*/ */
private static MediaViewVideoPanel getFXImpl() { private static MediaViewVideoPanel getFXImpl() {
if (fxVideoPanel == null) { return new FXVideoPanel();
fxVideoPanel = new FXVideoPanel();
}
return fxVideoPanel;
} }
/** /**

View File

@ -42,6 +42,7 @@ public class ContextMenuExtensionPoint {
if (!providerActions.isEmpty()) { if (!providerActions.isEmpty()) {
actions.add(null); // Separator to set off this provider's actions. actions.add(null); // Separator to set off this provider's actions.
actions.addAll(provider.getActions()); actions.addAll(provider.getActions());
actions.add(null); // Separator to set off this provider's actions.
} }
} }
return actions; return actions;

View File

@ -52,7 +52,8 @@ public class JLnkParser {
} }
} }
public JLNK parse() { public JLNK parse() throws JLnkParserException {
try {
ByteBuffer bb = ByteBuffer.wrap(content); ByteBuffer bb = ByteBuffer.wrap(content);
bb.order(ByteOrder.LITTLE_ENDIAN); bb.order(ByteOrder.LITTLE_ENDIAN);
int header = bb.getInt(); int header = bb.getInt();
@ -210,7 +211,9 @@ public class JLnkParser {
driveType, volumeLabel, commonNetworkRelativeLinkFlags, driveType, volumeLabel, commonNetworkRelativeLinkFlags,
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode, networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
deviceName, deviceNameUnicode); deviceName, deviceNameUnicode);
} catch (Exception e) {
throw new JLnkParserException(e);
}
} }
private String readStringData(ByteBuffer bb) { private String readStringData(ByteBuffer bb) {
@ -337,3 +340,5 @@ public class JLnkParser {
return new String(nameArr).split("\0")[0]; return new String(nameArr).split("\0")[0];
} }
} }

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

View File

@ -146,6 +146,12 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
return "Known"; return "Known";
} }
}, },
HASHSETS {
@Override
public String toString() {
return "In Hashsets";
}
},
MD5HASH { MD5HASH {
@Override @Override
public String toString() { public String toString() {
@ -188,6 +194,7 @@ public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends A
map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel()); map.put(AbstractFilePropertyType.TYPE_DIR.toString(), content.getDirType().getLabel());
map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString()); map.put(AbstractFilePropertyType.TYPE_META.toString(), content.getMetaType().toString());
map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName()); map.put(AbstractFilePropertyType.KNOWN.toString(), content.getKnown().getName());
map.put(AbstractFilePropertyType.HASHSETS.toString(), HashsetHits.getList(content.getSleuthkitCase(), content.getId()));
map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash()); map.put(AbstractFilePropertyType.MD5HASH.toString(), content.getMd5Hash() == null ? "" : content.getMd5Hash());
} }

View File

@ -21,7 +21,6 @@ package org.sleuthkit.autopsy.datamodel;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children.Keys; import org.openide.nodes.Children.Keys;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.datamodel.DerivedFile; import org.sleuthkit.datamodel.DerivedFile;
import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Directory;
@ -157,8 +156,8 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
} }
@Override @Override
public AbstractNode visit(Tags t) { public AbstractNode visit(TagsNodeKey tagsNodeKey) {
return t.new TagsRootNode(); return new TagsNode();
} }
@Override @Override

View File

@ -128,11 +128,6 @@ public class ArtifactTypeNode extends DisplayableItemNode {
return "artifact-icon.png"; return "artifact-icon.png";
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -52,7 +52,7 @@ public interface AutopsyItemVisitor<T> {
T visit(EmailExtracted ee); T visit(EmailExtracted ee);
T visit(Tags t); T visit(TagsNodeKey tagsNodeKey);
T visit(DataSources i); T visit(DataSources i);
@ -135,8 +135,8 @@ public interface AutopsyItemVisitor<T> {
} }
@Override @Override
public T visit(Tags t) { public T visit(TagsNodeKey tagsNodeKey) {
return defaultVisit(t); return defaultVisit(tagsNodeKey);
} }
@Override @Override

View File

@ -19,6 +19,7 @@
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -45,6 +46,15 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
private Content associated; private Content associated;
private List<NodeProperty> customProperties; private List<NodeProperty> customProperties;
static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName()); static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
/**
* Artifact types which should have the associated content's full unique path
* as a property.
*/
private static final Integer[] SHOW_UNIQUE_PATH = new Integer[] {
BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID(),
};
/** /**
* Construct blackboard artifact node from an artifact and using provided * Construct blackboard artifact node from an artifact and using provided
@ -107,30 +117,38 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
entry.getValue())); entry.getValue()));
} }
String path = "";
try {
path = associated.getUniquePath();
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on " + associated);
}
final int artifactTypeID = artifact.getArtifactTypeID();
//custom additional properties
//TODO use addNodeProperty() instead of hardcoding here
if (artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()
|| artifactTypeID == BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
ss.put(new NodeProperty("File Path",
"File Path",
NO_DESCR,
path));
}
//append custom node properties //append custom node properties
if (customProperties != null) { if (customProperties != null) {
for (NodeProperty np : customProperties) { for (NodeProperty np : customProperties) {
ss.put(np); ss.put(np);
} }
}
final int artifactTypeId = artifact.getArtifactTypeID();
if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
String sourcePath = "";
try {
sourcePath = associated.getUniquePath();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to get unique path from: " + associated.getName());
}
if (sourcePath.isEmpty() == false) {
ss.put(new NodeProperty("File Path", "File Path",
NO_DESCR, sourcePath));
}
} else {
String dataSource = "";
try {
dataSource = associated.getImage().getName();
} catch (TskCoreException ex) {
logger.log(Level.WARNING, "Failed to get image name from " + associated.getName());
}
if (dataSource.isEmpty() == false) {
ss.put(new NodeProperty("Data Source", "Data Source",
NO_DESCR, dataSource));
}
} }
return s; return s;
@ -316,11 +334,6 @@ public class BlackboardArtifactNode extends DisplayableItemNode {
return "artifact-icon.png"; return "artifact-icon.png";
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

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

View File

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

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

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

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

View File

@ -39,8 +39,8 @@ public class DataSourcesNode extends DisplayableItemNode {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.CONTENT; return false;
} }
@Override @Override

View File

@ -109,8 +109,8 @@ public class DeletedContent implements AutopsyVisitableItem {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.META; return false;
} }
@Override @Override
@ -199,11 +199,6 @@ public class DeletedContent implements AutopsyVisitableItem {
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -22,9 +22,9 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.Action; import javax.swing.Action;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Directory; import org.sleuthkit.datamodel.Directory;
@ -77,7 +77,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]); return actions.toArray(new Action[0]);
} }
@ -93,7 +93,7 @@ public class DirectoryNode extends AbstractFsContentNode<AbstractFile> {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.CONTENT; return false;
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,12 +18,9 @@
*/ */
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.awt.datatransfer.Transferable;
import org.openide.nodes.AbstractNode; import org.openide.nodes.AbstractNode;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.util.Lookup; import org.openide.util.Lookup;
import org.openide.util.datatransfer.PasteType;
/** /**
* Interface for all displayable Nodes * Interface for all displayable Nodes
@ -38,34 +35,6 @@ public abstract class DisplayableItemNode extends AbstractNode {
super(children, lookup); super(children, lookup);
} }
abstract public boolean isLeafTypeNode();
/**
* Possible sub-implementations
*/
public enum TYPE {
CONTENT, ///< content node, such as file, image
ARTIFACT, ///< artifact data node
META, ///< top-level category node, such as view, filters, etc.
};
/**
* Get possible subtype of the displayable item node
* @return
*/
public abstract TYPE getDisplayableItemNodeType();
public boolean isLeafTypeNode() {
return false;
}
/**
* Visitor pattern support.
*
* @param v visitor
* @return visitor's visit return value
*/
public abstract <T> T accept(DisplayableItemNodeVisitor<T> v); public abstract <T> T accept(DisplayableItemNodeVisitor<T> v);
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -30,12 +30,10 @@ import org.sleuthkit.autopsy.datamodel.HashsetHits.HashsetHitsSetNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsKeywordNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsListNode;
import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode; import org.sleuthkit.autopsy.datamodel.KeywordHits.KeywordHitsRootNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; import org.sleuthkit.autopsy.directorytree.BlackboardArtifactTagTypeNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
import org.sleuthkit.autopsy.datamodel.Tags.TagsRootNode;
/** /**
* Visitor pattern for DisplayableItemNodes * Visitor pattern implementation for DisplayableItemNodes
*/ */
public interface DisplayableItemNodeVisitor<T> { public interface DisplayableItemNodeVisitor<T> {
@ -85,11 +83,17 @@ public interface DisplayableItemNodeVisitor<T> {
T visit(EmailExtractedFolderNode eefn); T visit(EmailExtractedFolderNode eefn);
T visit(TagsRootNode bksrn); T visit(TagsNode node);
T visit(TagsNodeRoot bksrn); T visit(TagNameNode node);
T visit(TagNodeRoot tnr); T visit(ContentTagTypeNode node);
T visit(ContentTagNode node);
T visit(BlackboardArtifactTagTypeNode node);
T visit(BlackboardArtifactTagNode node);
T visit(ViewsNode vn); T visit(ViewsNode vn);
@ -265,18 +269,33 @@ public interface DisplayableItemNodeVisitor<T> {
} }
@Override @Override
public T visit(TagsRootNode bksrn) { public T visit(TagsNode node) {
return defaultVisit(bksrn); return defaultVisit(node);
} }
@Override @Override
public T visit(TagsNodeRoot bksnr) { public T visit(TagNameNode node) {
return defaultVisit(bksnr); return defaultVisit(node);
} }
@Override @Override
public T visit(TagNodeRoot tnr) { public T visit(ContentTagTypeNode node) {
return defaultVisit(tnr); return defaultVisit(node);
}
@Override
public T visit(ContentTagNode node) {
return defaultVisit(node);
}
@Override
public T visit(BlackboardArtifactTagTypeNode node) {
return defaultVisit(node);
}
@Override
public T visit(BlackboardArtifactTagNode node) {
return defaultVisit(node);
} }
} }
} }

View File

@ -133,8 +133,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.ARTIFACT; return false;
} }
@Override @Override
@ -173,6 +173,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected boolean createKeys(List<BlackboardArtifact> list) {
//flatten all emails //flatten all emails
List<BlackboardArtifact> tempList = new ArrayList<>();
for (String account : accounts.keySet()) { for (String account : accounts.keySet()) {
Map<String, List<Long>> folders = accounts.get(account); Map<String, List<Long>> folders = accounts.get(account);
for (String folder : folders.keySet()) { for (String folder : folders.keySet()) {
@ -180,7 +181,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
for (long l : messages) { for (long l : messages) {
try { try {
//TODO: bulk artifact gettings //TODO: bulk artifact gettings
list.add(skCase.getBlackboardArtifact(l)); tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
} }
@ -189,7 +190,7 @@ public class EmailExtracted implements AutopsyVisitableItem {
} }
list.addAll(tempList);
return true; return true;
} }
@ -214,8 +215,8 @@ public class EmailExtracted implements AutopsyVisitableItem {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.ARTIFACT; return false;
} }
@Override @Override
@ -271,11 +272,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/account-icon-16.png");
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
@ -293,6 +289,11 @@ public class EmailExtracted implements AutopsyVisitableItem {
return s; return s;
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -336,11 +337,6 @@ public class EmailExtracted implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/folder-icon-16.png");
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;
@ -383,14 +379,16 @@ public class EmailExtracted implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected boolean createKeys(List<BlackboardArtifact> list) {
List<BlackboardArtifact> tempList = new ArrayList<>();
for (long l : messages) { for (long l : messages) {
try { try {
//TODO: bulk artifact gettings //TODO: bulk artifact gettings
list.add(skCase.getBlackboardArtifact(l)); tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "Error creating mail messages nodes", ex); logger.log(Level.WARNING, "Error creating mail messages nodes", ex);
} }
} }
list.addAll(tempList);
return true; return true;
} }

View File

@ -38,6 +38,11 @@ public class ExtractedContentNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/extracted_content.png");
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -58,9 +63,4 @@ public class ExtractedContentNode extends DisplayableItemNode {
NAME)); NAME));
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
} }

View File

@ -22,11 +22,11 @@ import java.util.ArrayList;
import java.util.List; import java.util.List;
import javax.swing.Action; import javax.swing.Action;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.autopsy.directorytree.ViewContextAction; import org.sleuthkit.autopsy.directorytree.ViewContextAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
@ -85,7 +85,7 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
actionsList.add(ExtractAction.getInstance()); actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance()); actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions()); actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }
@ -170,13 +170,8 @@ public class FileNode extends AbstractFsContentNode<AbstractFile> {
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; //false; return true;
} }
} }

View File

@ -111,8 +111,8 @@ public class FileSize implements AutopsyVisitableItem {
} }
@Override @Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return DisplayableItemNode.TYPE.META; return false;
} }
@Override @Override
@ -201,11 +201,6 @@ public class FileSize implements AutopsyVisitableItem {
return s; return s;
} }
@Override
public DisplayableItemNode.TYPE getDisplayableItemNodeType() {
return DisplayableItemNode.TYPE.META;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -78,11 +78,6 @@ public class FileTypeNode extends DisplayableItemNode {
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -52,6 +52,11 @@ public class FileTypesNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -72,9 +77,4 @@ public class FileTypesNode extends DisplayableItemNode {
getName())); getName()));
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
} }

View File

@ -94,6 +94,43 @@ public class HashsetHits implements AutopsyVisitableItem {
} }
} }
static public String getList(SleuthkitCase skCase, long objId) {
ResultSet rs = null;
String strList = "";
try {
int setNameId = BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID();
int artId = BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID();
String query = "SELECT value_text,blackboard_attributes.artifact_id,attribute_type_id "
+ "FROM blackboard_attributes,blackboard_artifacts WHERE "
+ "attribute_type_id=" + setNameId
+ " AND blackboard_attributes.artifact_id=blackboard_artifacts.artifact_id"
+ " AND blackboard_artifacts.artifact_type_id=" + artId
+ " AND blackboard_artifacts.obj_id=" + objId;
rs = skCase.runQuery(query);
int i = 0;
while (rs.next()) {
if (i++ > 0) {
strList += ", ";
}
strList += rs.getString("value_text");
}
} catch (SQLException ex) {
logger.log(Level.WARNING, "SQL Exception occurred: ", ex);
}
finally {
if (rs != null) {
try {
skCase.closeRunQuery(rs);
} catch (SQLException ex) {
logger.log(Level.WARNING, "Error closing result set after getting hashset hits", ex);
}
}
}
return strList;
}
@Override @Override
public <T> T accept(AutopsyItemVisitor<T> v) { public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -113,8 +150,8 @@ public class HashsetHits implements AutopsyVisitableItem {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.ARTIFACT; return false;
} }
@Override @Override
@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -56,11 +56,6 @@ public class ImageNode extends AbstractContentNode<Image> {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hard-drive-icon.jpg");
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
/** /**
* Right click action for this node * Right click action for this node
* *
@ -98,6 +93,11 @@ public class ImageNode extends AbstractContentNode<Image> {
return v.visit(this); return v.visit(this);
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);

View File

@ -20,7 +20,7 @@ package org.sleuthkit.autopsy.datamodel;
import java.sql.ResultSet; import java.sql.ResultSet;
import java.sql.SQLException; import java.sql.SQLException;
import java.sql.Statement; import java.util.ArrayList;
import java.util.HashSet; import java.util.HashSet;
import java.util.LinkedHashMap; import java.util.LinkedHashMap;
import java.util.List; import java.util.List;
@ -28,16 +28,18 @@ import java.util.Map;
import java.util.Set; import java.util.Set;
import java.util.logging.Level; import java.util.logging.Level;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.ChildFactory; import org.openide.nodes.ChildFactory;
import org.openide.nodes.Children; import org.openide.nodes.Children;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.Exceptions;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskException; import org.sleuthkit.datamodel.TskException;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.TskCoreException;
/** /**
* Keyword hits node support * Keyword hits node support
@ -170,13 +172,13 @@ public class KeywordHits implements AutopsyVisitableItem {
} }
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public boolean isLeafTypeNode() {
return v.visit(this); return false;
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return TYPE.ARTIFACT; return v.visit(this);
} }
@Override @Override
@ -229,11 +231,6 @@ public class KeywordHits implements AutopsyVisitableItem {
this.children = children; this.children = children;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
@ -257,6 +254,11 @@ public class KeywordHits implements AutopsyVisitableItem {
return s; return s;
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -310,11 +312,6 @@ public class KeywordHits implements AutopsyVisitableItem {
return v.visit(this); return v.visit(this);
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
@ -327,11 +324,11 @@ public class KeywordHits implements AutopsyVisitableItem {
ss.put(new NodeProperty("List Name", ss.put(new NodeProperty("List Name",
"List Name", "List Name",
"no description", "no description",
name)); getDisplayName()));
ss.put(new NodeProperty("Number of Hits", ss.put(new NodeProperty("Files with Hits",
"Number of Hits", "Files with Hits",
"no description", "no description",
children.size())); children.size()));
@ -350,20 +347,44 @@ public class KeywordHits implements AutopsyVisitableItem {
@Override @Override
protected boolean createKeys(List<BlackboardArtifact> list) { protected boolean createKeys(List<BlackboardArtifact> list) {
List<BlackboardArtifact> tempList = new ArrayList<>();
for (long l : children) { for (long l : children) {
try { try {
//TODO: bulk artifact gettings //TODO: bulk artifact gettings
list.add(skCase.getBlackboardArtifact(l)); tempList.add(skCase.getBlackboardArtifact(l));
} catch (TskException ex) { } catch (TskException ex) {
logger.log(Level.WARNING, "TSK Exception occurred", ex); logger.log(Level.WARNING, "TSK Exception occurred", ex);
} }
} }
list.addAll(tempList);
return true; return true;
} }
@Override @Override
protected Node createNodeForKey(BlackboardArtifact artifact) { protected Node createNodeForKey(BlackboardArtifact artifact) {
return new BlackboardArtifactNode(artifact); BlackboardArtifactNode n = new BlackboardArtifactNode(artifact);
AbstractFile file;
try {
file = artifact.getSleuthkitCase().getAbstractFileById(artifact.getObjectID());
} catch (TskCoreException ex) {
logger.log(Level.SEVERE, "TskCoreException while constructing BlackboardArtifact Node from KeywordHitsKeywordChildren");
return n;
}
n.addNodeProperty(new NodeProperty("ModifiedTime",
"Modified Time",
"Modified Time",
ContentUtils.getStringTime(file.getMtime(), file)));
n.addNodeProperty(new NodeProperty("AccessTime",
"Access Time",
"Access Time",
ContentUtils.getStringTime(file.getAtime(), file)));
n.addNodeProperty(new NodeProperty("ChangeTime",
"Change Time",
"Change Time",
ContentUtils.getStringTime(file.getCtime(), file)));
return n;
} }
} }
} }

View File

@ -28,7 +28,7 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.datamodel.LayoutFile; import org.sleuthkit.datamodel.LayoutFile;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -63,11 +63,6 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
} }
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
@ -96,6 +91,11 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
return v.visit(this); return v.visit(this);
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -109,7 +109,7 @@ public class LayoutFileNode extends AbstractAbstractFileNode<LayoutFile> {
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(ExtractAction.getInstance()); actionsList.add(ExtractAction.getInstance());
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance()); actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions()); actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }

View File

@ -26,12 +26,11 @@ import java.util.Map;
import javax.swing.Action; import javax.swing.Action;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint; import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.datamodel.DisplayableItemNode.TYPE;
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction; import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.HashSearchAction; import org.sleuthkit.autopsy.directorytree.HashSearchAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction; import org.sleuthkit.autopsy.actions.AddContentTagAction;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
/** /**
@ -56,11 +55,6 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override @Override
protected Sheet createSheet() { protected Sheet createSheet() {
Sheet s = super.createSheet(); Sheet s = super.createSheet();
@ -93,7 +87,7 @@ public class LocalFileNode extends AbstractAbstractFileNode<AbstractFile> {
actionsList.add(ExtractAction.getInstance()); actionsList.add(ExtractAction.getInstance());
actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this)); actionsList.add(new HashSearchAction("Search for files with the same MD5 hash", this));
actionsList.add(null); // creates a menu separator actionsList.add(null); // creates a menu separator
actionsList.add(TagAbstractFileAction.getInstance()); actionsList.add(AddContentTagAction.getInstance());
actionsList.addAll(ContextMenuExtensionPoint.getActions()); actionsList.addAll(ContextMenuExtensionPoint.getActions());
return actionsList.toArray(new Action[0]); return actionsList.toArray(new Action[0]);
} }

View File

@ -79,11 +79,6 @@ public class RecentFilesFilterNode extends DisplayableItemNode {
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -42,8 +42,8 @@ public class RecentFilesNode extends DisplayableItemNode {
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public boolean isLeafTypeNode() {
return TYPE.META; return false;
} }
@Override @Override

View File

@ -19,7 +19,6 @@
package org.sleuthkit.autopsy.datamodel; package org.sleuthkit.autopsy.datamodel;
import java.util.Arrays; import java.util.Arrays;
import org.openide.nodes.AbstractNode;
import org.openide.nodes.Sheet; import org.openide.nodes.Sheet;
import org.openide.util.lookup.Lookups; import org.openide.util.lookup.Lookups;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
@ -36,13 +35,18 @@ public class ResultsNode extends DisplayableItemNode {
new KeywordHits(sleuthkitCase), new KeywordHits(sleuthkitCase),
new HashsetHits(sleuthkitCase), new HashsetHits(sleuthkitCase),
new EmailExtracted(sleuthkitCase), new EmailExtracted(sleuthkitCase),
new Tags(sleuthkitCase) //TODO move to the top of the tree new TagsNodeKey()
)), Lookups.singleton(NAME)); )), Lookups.singleton(NAME));
setName(NAME); setName(NAME);
setDisplayName(NAME); setDisplayName(NAME);
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/results.png");
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -63,9 +67,4 @@ public class ResultsNode extends DisplayableItemNode {
NAME)); NAME));
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
} }

View File

@ -80,16 +80,9 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
if (o instanceof EmailExtracted) if (o instanceof EmailExtracted)
this.refreshKey(o); this.refreshKey(o);
break; break;
//TODO check
case TSK_TAG_FILE: case TSK_TAG_FILE:
if (o instanceof Tags)
this.refreshKey(o);
break;
//TODO check
case TSK_TAG_ARTIFACT: case TSK_TAG_ARTIFACT:
if (o instanceof Tags) if (o instanceof TagsNodeKey)
this.refreshKey(o); this.refreshKey(o);
break; break;
default: default:
@ -105,7 +98,7 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
this.refreshKey(o); this.refreshKey(o);
else if (o instanceof EmailExtracted) else if (o instanceof EmailExtracted)
this.refreshKey(o); this.refreshKey(o);
else if (o instanceof Tags) else if (o instanceof TagsNodeKey)
this.refreshKey(o); this.refreshKey(o);
else if (o instanceof ExtractedContent) else if (o instanceof ExtractedContent)
this.refreshKey(o); this.refreshKey(o);

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

View File

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

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

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

View File

@ -45,6 +45,11 @@ public class ViewsNode extends DisplayableItemNode {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png"); this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/views.png");
} }
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this); return v.visit(this);
@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
NAME)); NAME));
return s; return s;
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
} }

View File

@ -28,7 +28,6 @@ import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.directorytree.ExtractAction; import org.sleuthkit.autopsy.directorytree.ExtractAction;
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction; import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
import org.sleuthkit.autopsy.directorytree.TagAbstractFileAction;
import org.sleuthkit.datamodel.VirtualDirectory; import org.sleuthkit.datamodel.VirtualDirectory;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
@ -82,7 +81,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions.toArray(new Action[0]); return actions.toArray(new Action[0]);
} }
@ -120,11 +118,6 @@ public class VirtualDirectoryNode extends AbstractAbstractFileNode<VirtualDirect
return v.visit(this); return v.visit(this);
} }
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
}
@Override @Override
public boolean isLeafTypeNode() { public boolean isLeafTypeNode() {
return true; return true;

View File

@ -101,12 +101,12 @@ public class VolumeNode extends AbstractContentNode<Volume> {
} }
@Override @Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) { public boolean isLeafTypeNode() {
return v.visit(this); return false;
} }
@Override @Override
public TYPE getDisplayableItemNodeType() { public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return TYPE.CONTENT; return v.visit(this);
} }
} }

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

View File

@ -47,17 +47,3 @@ ImageDetailsPanel.imgSectorSizeLabel.text=Sector Size:
ImageDetailsPanel.imgSectorSizeValue.text=... ImageDetailsPanel.imgSectorSizeValue.text=...
DirectoryTreeTopComponent.backButton.text= DirectoryTreeTopComponent.backButton.text=
DirectoryTreeTopComponent.forwardButton.text= DirectoryTreeTopComponent.forwardButton.text=
CreateTagDialog.cancelButton.text=Cancel
CreateTagDialog.okButton.text=OK
CreateTagDialog.tagNameField.text=
CreateTagDialog.tagNameLabel.text=Tag Name:
CreateTagDialog.preexistingLabel.text=Pre-existing Tags:
CreateTagDialog.newTagPanel.border.title=New Tag
TagAndCommentDialog.tagLabel.text=Tag:
TagAndCommentDialog.tagCombo.toolTipText=Select tag to use
TagAndCommentDialog.cancelButton.text=Cancel
TagAndCommentDialog.okButton.text=OK
TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
TagAndCommentDialog.commentText.text=
TagAndCommentDialog.commentLabel.text=Comment:
TagAndCommentDialog.newTagButton.text=New Tag

View File

@ -18,6 +18,8 @@
*/ */
package org.sleuthkit.autopsy.directorytree; package org.sleuthkit.autopsy.directorytree;
import org.sleuthkit.autopsy.actions.AddBlackboardArtifactTagAction;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.beans.PropertyVetoException; import java.beans.PropertyVetoException;
import java.util.ArrayList; import java.util.ArrayList;
@ -38,6 +40,7 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode.AbstractFileProp
import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode; import org.sleuthkit.autopsy.datamodel.AbstractFsContentNode;
import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode; import org.sleuthkit.autopsy.datamodel.ArtifactTypeNode;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode; import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
import org.sleuthkit.autopsy.datamodel.ContentTagTypeNode;
import org.sleuthkit.autopsy.datamodel.LocalFileNode; import org.sleuthkit.autopsy.datamodel.LocalFileNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsChildren.DeletedContentNode;
import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode; import org.sleuthkit.autopsy.datamodel.DeletedContent.DeletedContentsNode;
@ -62,8 +65,7 @@ import org.sleuthkit.autopsy.datamodel.LayoutFileNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode; import org.sleuthkit.autopsy.datamodel.RecentFilesFilterNode;
import org.sleuthkit.autopsy.datamodel.RecentFilesNode; import org.sleuthkit.autopsy.datamodel.RecentFilesNode;
import org.sleuthkit.autopsy.datamodel.FileTypesNode; import org.sleuthkit.autopsy.datamodel.FileTypesNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagNodeRoot; import org.sleuthkit.autopsy.datamodel.TagNameNode;
import org.sleuthkit.autopsy.datamodel.Tags.TagsNodeRoot;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardAttribute; import org.sleuthkit.datamodel.BlackboardAttribute;
@ -169,6 +171,8 @@ public class DataResultFilterNode extends FilterNode {
//set up actions for artifact node based on its Content object //set up actions for artifact node based on its Content object
//TODO all actions need to be consolidated in single place! //TODO all actions need to be consolidated in single place!
//they should be set in individual Node subclass and using a utility to get Actions per Content sub-type //they should be set in individual Node subclass and using a utility to get Actions per Content sub-type
// TODO UPDATE: There is now a DataModelActionsFactory utility; also tags are no longer artifacts so conditionals
// can be removed.
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
@ -207,8 +211,8 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance()); actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
} }
} }
@ -224,8 +228,8 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance()); actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
} }
} }
@ -241,8 +245,8 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance()); actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
} }
} else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) { } else if ((lf = ban.getLookup().lookup(LayoutFile.class)) != null) {
@ -257,8 +261,8 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance()); actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
} }
} else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null } else if ((locF = ban.getLookup().lookup(LocalFile.class)) != null
@ -274,8 +278,8 @@ public class DataResultFilterNode extends FilterNode {
if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID() if (artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE.getTypeID()
&& artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) { && artifactTypeID != BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT.getTypeID()) {
actions.add(null); // creates a menu separator actions.add(null); // creates a menu separator
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.add(TagBlackboardArtifactAction.getInstance()); actions.add(AddBlackboardArtifactTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
} }
} }
@ -410,13 +414,18 @@ public class DataResultFilterNode extends FilterNode {
} }
@Override @Override
public AbstractAction visit(TagNodeRoot tnr) { public AbstractAction visit(TagNameNode node) {
return openChild(tnr); return openChild(node);
} }
@Override @Override
public AbstractAction visit(TagsNodeRoot tnr) { public AbstractAction visit(ContentTagTypeNode node) {
return openChild(tnr); return openChild(node);
}
@Override
public AbstractAction visit(BlackboardArtifactTagTypeNode node) {
return openChild(node);
} }
@Override @Override

View File

@ -27,6 +27,7 @@ import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener; import java.beans.PropertyChangeListener;
import java.beans.PropertyChangeSupport; import java.beans.PropertyChangeSupport;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedList; import java.util.LinkedList;
import java.util.List; import java.util.List;
import java.util.logging.Level; import java.util.logging.Level;
@ -804,7 +805,7 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
* Refreshes the nodes in the tree to reflect updates in the database should * Refreshes the nodes in the tree to reflect updates in the database should
* be called in the gui thread * be called in the gui thread
*/ */
void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) { public void refreshTree(final BlackboardArtifact.ARTIFACT_TYPE... types) {
//save current selection //save current selection
Node selectedNode = getSelectedNode(); Node selectedNode = getSelectedNode();
final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext()); final String[] selectedPath = NodeOp.createPath(selectedNode, em.getRootContext());
@ -856,38 +857,53 @@ public final class DirectoryTreeTopComponent extends TopComponent implements Dat
} }
/** /**
* Set selected node using the previously saved selection path to the * Set the selected node using a path to a previously selected node.
* selected node
* *
* @param path node path with node names * @param previouslySelectedNodePath Path to a previously selected node.
* @param rootNodeName name of the root node to match or null if any * @param rootNodeName Name of the root node to match, may be null.
*/ */
private void setSelectedNode(final String[] path, final String rootNodeName) { private void setSelectedNode(final String[] previouslySelectedNodePath, final String rootNodeName) {
if (path == null) { if (previouslySelectedNodePath == null) {
return; return;
} }
SwingUtilities.invokeLater(new Runnable() { SwingUtilities.invokeLater(new Runnable() {
@Override @Override
public void run() { public void run() {
if (previouslySelectedNodePath.length > 0 && (rootNodeName == null || previouslySelectedNodePath[0].equals(rootNodeName))) {
if (path.length > 0 && (rootNodeName == null || path[0].equals(rootNodeName))) { Node selectedNode = null;
ArrayList<String> selectedNodePath = new ArrayList<>(Arrays.asList(previouslySelectedNodePath));
while (null == selectedNode && !selectedNodePath.isEmpty()) {
try { try {
Node newSelection = NodeOp.findPath(em.getRootContext(), path); selectedNode = NodeOp.findPath(em.getRootContext(), selectedNodePath.toArray(new String[0]));
}
catch (NodeNotFoundException ex) {
// The selected node may have been deleted (e.g., a deleted tag), so truncate the path and try again.
if (selectedNodePath.size() > 1) {
selectedNodePath.remove(selectedNodePath.size() - 1);
}
else {
StringBuilder nodePath = new StringBuilder();
for (int i = 0; i < previouslySelectedNodePath.length; ++i) {
nodePath.append(previouslySelectedNodePath[i]).append("/");
}
logger.log(Level.WARNING, "Failed to find any nodes to select on path " + nodePath.toString(), ex);
break;
}
}
}
if (newSelection != null) { if (null != selectedNode) {
if (rootNodeName != null) { if (rootNodeName != null) {
//called from tree auto refresh context //called from tree auto refresh context
//remove last from backlist, because auto select will result in duplication //remove last from backlist, because auto select will result in duplication
backList.pollLast(); backList.pollLast();
} }
em.setExploredContextAndSelection(newSelection, new Node[]{newSelection}); try {
em.setExploredContextAndSelection(selectedNode, new Node[]{selectedNode});
}
catch (PropertyVetoException ex) {
logger.log(Level.WARNING, "Property veto from ExplorerManager setting selection to " + selectedNode.getName(), ex);
} }
// We need to set the selection, which will refresh dataresult and get rid of the oob exception
} catch (NodeNotFoundException ex) {
logger.log(Level.WARNING, "Node not found", ex);
} catch (PropertyVetoException ex) {
logger.log(Level.WARNING, "Property Veto", ex);
} }
} }
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -18,6 +18,7 @@
*/ */
package org.sleuthkit.autopsy.directorytree; package org.sleuthkit.autopsy.directorytree;
import org.sleuthkit.autopsy.actions.AddContentTagAction;
import java.awt.Toolkit; import java.awt.Toolkit;
import java.awt.Dimension; import java.awt.Dimension;
import java.awt.Font; import java.awt.Font;
@ -102,7 +103,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
@Override @Override
public List<? extends Action> visit(final Directory d) { public List<? extends Action> visit(final Directory d) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions; return actions;
} }
@ -111,7 +112,6 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
public List<? extends Action> visit(final VirtualDirectory d) { public List<? extends Action> visit(final VirtualDirectory d) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions; return actions;
} }
@ -120,7 +120,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
public List<? extends Action> visit(final DerivedFile d) { public List<? extends Action> visit(final DerivedFile d) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions; return actions;
} }
@ -129,7 +129,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
public List<? extends Action> visit(final LocalFile d) { public List<? extends Action> visit(final LocalFile d) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions; return actions;
} }
@ -138,7 +138,7 @@ public class ExplorerNodeActionVisitor extends ContentVisitor.Default<List<? ext
public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) { public List<? extends Action> visit(final org.sleuthkit.datamodel.File d) {
List<Action> actions = new ArrayList<>(); List<Action> actions = new ArrayList<>();
actions.add(ExtractAction.getInstance()); actions.add(ExtractAction.getInstance());
actions.add(TagAbstractFileAction.getInstance()); actions.add(AddContentTagAction.getInstance());
actions.addAll(ContextMenuExtensionPoint.getActions()); actions.addAll(ContextMenuExtensionPoint.getActions());
return actions; return actions;
} }

View File

@ -22,6 +22,7 @@ package org.sleuthkit.autopsy.directorytree;
import java.awt.event.ActionEvent; import java.awt.event.ActionEvent;
import java.util.logging.Level; import java.util.logging.Level;
import javax.swing.AbstractAction; import javax.swing.AbstractAction;
import javax.swing.SwingUtilities;
import org.openide.nodes.Node; import org.openide.nodes.Node;
import org.openide.windows.Mode; import org.openide.windows.Mode;
import org.openide.windows.WindowManager; import org.openide.windows.WindowManager;
@ -63,12 +64,20 @@ public class NewWindowViewAction extends AbstractAction{
} }
} }
DataContentTopComponent dctc = DataContentTopComponent.createUndocked(name, this.contentNode); final DataContentTopComponent dctc = DataContentTopComponent.createUndocked(name, null);
Mode m = WindowManager.getDefault().findMode("outputFloat"); Mode m = WindowManager.getDefault().findMode("outputFloat");
m.dockInto(dctc); m.dockInto(dctc);
dctc.open(); dctc.open();
// Queue setting the node on the EDT thread to be done later so the dctc
// can completely initialize.
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
dctc.setNode(contentNode);
}
});
} }

View File

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

View File

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

View File

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

View File

@ -24,7 +24,7 @@ FileSearchTopComponent.dateCheckBox1.text=Date:
FileSearchTopComponent.dateFiltersButton1.text=Date Filters FileSearchTopComponent.dateFiltersButton1.text=Date Filters
KnownStatusSearchPanel.knownCheckBox.text=Known Status: KnownStatusSearchPanel.knownCheckBox.text=Known Status:
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL) KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
DateSearchPanel.dateCheckBox.text=Date: DateSearchPanel.dateCheckBox.text=Date:
DateSearchPanel.jLabel4.text=Timezone: DateSearchPanel.jLabel4.text=Timezone:

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011 Basis Technology Corp. * Copyright 2011 - 2013 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -55,7 +55,7 @@ class KnownStatusSearchFilter extends AbstractFileSearchFilter<KnownStatusSearch
String expr = "0"; String expr = "0";
if (unknown) { if (unknown) {
expr += " or " + predicateHelper(FileKnown.UKNOWN); expr += " or " + predicateHelper(FileKnown.UNKNOWN);
} }
if (known) { if (known) {
expr += " or " + predicateHelper(FileKnown.KNOWN); expr += " or " + predicateHelper(FileKnown.KNOWN);

View File

@ -1,4 +1,4 @@
<?xml version="1.1" encoding="UTF-8" ?> <?xml version="1.0" encoding="UTF-8" ?>
<Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo"> <Form version="1.5" maxVersion="1.7" type="org.netbeans.modules.form.forminfo.JPanelFormInfo">
<AuxValues> <AuxValues>
@ -64,6 +64,9 @@
<ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/> <ResourceString bundle="org/sleuthkit/autopsy/filesearch/Bundle.properties" key="KnownStatusSearchPanel.knownOptionCheckBox.text" replaceFormat="org.openide.util.NbBundle.getMessage({sourceFileName}.class, &quot;{key}&quot;)"/>
</Property> </Property>
</Properties> </Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
</Events>
</Component> </Component>
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox"> <Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
<Properties> <Properties>

View File

@ -74,6 +74,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
knownOptionCheckBox.setSelected(true); knownOptionCheckBox.setSelected(true);
knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N knownOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownOptionCheckBox.text")); // NOI18N
knownOptionCheckBox.addActionListener(new java.awt.event.ActionListener() {
public void actionPerformed(java.awt.event.ActionEvent evt) {
knownOptionCheckBoxActionPerformed(evt);
}
});
knownBadOptionCheckBox.setSelected(true); knownBadOptionCheckBox.setSelected(true);
knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N knownBadOptionCheckBox.setText(org.openide.util.NbBundle.getMessage(KnownStatusSearchPanel.class, "KnownStatusSearchPanel.knownBadOptionCheckBox.text")); // NOI18N
@ -102,6 +107,11 @@ class KnownStatusSearchPanel extends javax.swing.JPanel {
.addComponent(knownBadOptionCheckBox)) .addComponent(knownBadOptionCheckBox))
); );
}// </editor-fold>//GEN-END:initComponents }// </editor-fold>//GEN-END:initComponents
private void knownOptionCheckBoxActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_knownOptionCheckBoxActionPerformed
// TODO add your handling code here:
}//GEN-LAST:event_knownOptionCheckBoxActionPerformed
// Variables declaration - do not modify//GEN-BEGIN:variables // Variables declaration - do not modify//GEN-BEGIN:variables
private javax.swing.JCheckBox knownBadOptionCheckBox; private javax.swing.JCheckBox knownBadOptionCheckBox;
private javax.swing.JCheckBox knownCheckBox; private javax.swing.JCheckBox knownCheckBox;

View File

@ -65,6 +65,9 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", "); String[] enabledModuleNames = ModuleSettings.getConfigSetting(moduleContext, ENABLED_INGEST_MODULES_KEY).split(", ");
List<IngestModuleAbstract> enabledModules = new ArrayList<>(); List<IngestModuleAbstract> enabledModules = new ArrayList<>();
for (String moduleName : enabledModuleNames) { for (String moduleName : enabledModuleNames) {
if (moduleName.equals("Thunderbird Parser")) {
moduleName = "MBox Parser";
}
IngestModuleAbstract moduleFound = null; IngestModuleAbstract moduleFound = null;
for (IngestModuleAbstract module : allModules) { for (IngestModuleAbstract module : allModules) {
if (moduleName.equals(module.getName())) { if (moduleName.equals(module.getName())) {
@ -76,7 +79,7 @@ public class GeneralIngestConfigurator implements IngestConfigurator {
enabledModules.add(moduleFound); enabledModules.add(moduleFound);
} }
else { else {
messages.add("Unable to load " + moduleName + " module"); messages.add("Unable to enable ingest module: " + moduleName);
} }
} }
ingestDialogPanel.setEnabledIngestModules(enabledModules); ingestDialogPanel.setEnabledIngestModules(enabledModules);

View File

@ -47,6 +47,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
private IngestDataSourceWorkerController controller; private IngestDataSourceWorkerController controller;
private final IngestManager manager; private final IngestManager manager;
private final IngestModuleInit init; private final IngestModuleInit init;
private boolean inited;
//current method of enqueuing data source ingest modules with locks and internal lock queue //current method of enqueuing data source ingest modules with locks and internal lock queue
//ensures that we init, run and complete a single data source ingest module at a time //ensures that we init, run and complete a single data source ingest module at a time
//uses fairness policy to run them in order enqueued //uses fairness policy to run them in order enqueued
@ -59,6 +60,7 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
this.dataSource = dataSource; this.dataSource = dataSource;
this.module = module; this.module = module;
this.init = init; this.init = init;
this.inited = false;
} }
PipelineContext<IngestModuleDataSource>getContext() { PipelineContext<IngestModuleDataSource>getContext() {
@ -73,6 +75,20 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
return module; return module;
} }
public void init() {
logger.log(Level.INFO, "Initializing module: " + module.getName());
try {
module.init(init);
inited = true;
} catch (Exception e) {
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
//will not run
inited = false;
throw e;
}
}
@Override @Override
protected Void doInBackground() throws Exception { protected Void doInBackground() throws Exception {
@ -102,15 +118,10 @@ public class IngestDataSourceThread extends SwingWorker<Void, Void> {
logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo()); logger.log(Level.INFO, PlatformUtil.getAllMemUsageInfo());
progress.setDisplayName(displayName); progress.setDisplayName(displayName);
logger.log(Level.INFO, "Initializing module: " + module.getName()); if (inited == false) {
try { logger.log(Level.INFO, "Module wasn't initialized, will not run: " + module.getName());
module.init(init);
} catch (Exception e) {
logger.log(Level.INFO, "Failed initializing module: " + module.getName() + ", will not run.");
return Void.TYPE.newInstance(); return Void.TYPE.newInstance();
//will not run
} }
logger.log(Level.INFO, "Starting processing of module: " + module.getName()); logger.log(Level.INFO, "Starting processing of module: " + module.getName());
controller = new IngestDataSourceWorkerController(this, progress); controller = new IngestDataSourceWorkerController(this, progress);

View File

@ -37,6 +37,7 @@ import javax.swing.SwingWorker;
import org.netbeans.api.progress.ProgressHandle; import org.netbeans.api.progress.ProgressHandle;
import org.netbeans.api.progress.ProgressHandleFactory; import org.netbeans.api.progress.ProgressHandleFactory;
import org.openide.util.Cancellable; import org.openide.util.Cancellable;
import org.sleuthkit.autopsy.coreutils.MessageNotifyUtil;
import org.sleuthkit.autopsy.coreutils.PlatformUtil; import org.sleuthkit.autopsy.coreutils.PlatformUtil;
import org.sleuthkit.autopsy.coreutils.StopWatch; import org.sleuthkit.autopsy.coreutils.StopWatch;
import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType; import org.sleuthkit.autopsy.ingest.IngestMessage.MessageType;
@ -76,6 +77,7 @@ public class IngestManager {
private IngestModuleLoader moduleLoader = null; private IngestModuleLoader moduleLoader = null;
//property file name id for the module //property file name id for the module
public final static String MODULE_PROPERTIES = "ingest"; public final static String MODULE_PROPERTIES = "ingest";
private volatile int messageID = 0;
/** /**
* Possible events about ingest modules Event listeners can get the event * Possible events about ingest modules Event listeners can get the event
@ -84,40 +86,52 @@ public class IngestManager {
public enum IngestModuleEvent { public enum IngestModuleEvent {
/** /**
* Event sent when the ingest module has been started processing. Second * Event sent when an ingest module has been started. Second
* argument of the property change fired contains module name String and * argument of the property change is a string form of the module name
* third argument is null. * and the third argument is null.
*/ */
STARTED, STARTED,
/** /**
* Event sent when the ingest module has completed processing. Second * Event sent when an ingest module has completed processing by its own
* argument of the property change fired contains module name String and * means. Second
* third argument is null. * argument of the property change is a string form of the module name
* and the third argument is null.
* *
* This event is generally used by listeners to perform a final data * This event is generally used by listeners to perform a final data
* view refresh (listeners need to query all data from the blackboard). * view refresh (listeners need to query all data from the blackboard).
*
*/ */
COMPLETED, COMPLETED,
/** /**
* Event sent when the ingest module has stopped processing, and likely * Event sent when an ingest module has stopped processing, and likely
* not all data has been processed. Second argument of the property * not all data has been processed. Second argument of the property
* change fired contains module name String and third argument is null. * change is a string form of the module name and third argument is null.
*/ */
STOPPED, STOPPED,
/** /**
* Event sent when ingest module has new data. Second argument of the * Event sent when ingest module posts new data to blackboard or somewhere
* else. Second argument of the
* property change fired contains ModuleDataEvent object and third * property change fired contains ModuleDataEvent object and third
* argument is null. The object can contain encapsulated new data * argument is null. The object can contain encapsulated new data
* created by the module. Listener can also query new data as needed. * created by the module. Listener can also query new data as needed.
*
*/ */
DATA, DATA,
/** /**
* Event send when content changed, either its attributes changed, or * Event send when content changed, either its attributes changed, or
* new content children have been added * new content children have been added. I.e. from ZIP files or Carved files
*/ */
CONTENT_CHANGED CONTENT_CHANGED,
/**
* Event sent when a file has finished going through a pipeline of modules.
* Second argument is the object ID. Third argument is null
*/
FILE_DONE,
}; };
//ui //ui
//Initialized by Installer in AWT thread once the Window System is ready //Initialized by Installer in AWT thread once the Window System is ready
@ -183,9 +197,9 @@ public class IngestManager {
} }
/** /**
* Add property change listener to listen to ingest events * Add property change listener to listen to ingest events as defined in IngestModuleEvent.
* *
* @param l PropertyChangeListener to schedule * @param l PropertyChangeListener to register
*/ */
public static synchronized void addPropertyChangeListener(final PropertyChangeListener l) { public static synchronized void addPropertyChangeListener(final PropertyChangeListener l) {
pcs.addPropertyChangeListener(l); pcs.addPropertyChangeListener(l);
@ -195,10 +209,28 @@ public class IngestManager {
pcs.firePropertyChange(eventType, moduleName, null); pcs.firePropertyChange(eventType, moduleName, null);
} }
/**
* Fire event when file is done with a pipeline run
* @param objId ID of file that is done
*/
static synchronized void fireFileDone(long objId) {
pcs.firePropertyChange(IngestModuleEvent.FILE_DONE.toString(), objId, null);
}
/**
* Fire event for ModuleDataEvent (when modules post data to blackboard, etc.)
* @param moduleDataEvent
*/
static synchronized void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) { static synchronized void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
pcs.firePropertyChange(IngestModuleEvent.DATA.toString(), moduleDataEvent, null); pcs.firePropertyChange(IngestModuleEvent.DATA.toString(), moduleDataEvent, null);
} }
/**
* Fire event for ModuleContentChanged (when modules create new content that needs to be analyzed)
* @param moduleContentEvent
*/
static synchronized void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) { static synchronized void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {
pcs.firePropertyChange(IngestModuleEvent.CONTENT_CHANGED.toString(), moduleContentEvent, null); pcs.firePropertyChange(IngestModuleEvent.CONTENT_CHANGED.toString(), moduleContentEvent, null);
} }
@ -280,7 +312,8 @@ public class IngestManager {
} }
/** /**
* Starts the needed worker threads. * Starts the File-level Ingest Module pipeline and the Data Source-level Ingest Modules
* for the queued up data sources and files.
* *
* if AbstractFile module is still running, do nothing and allow it to * if AbstractFile module is still running, do nothing and allow it to
* consume queue otherwise start /restart AbstractFile worker * consume queue otherwise start /restart AbstractFile worker
@ -291,7 +324,9 @@ public class IngestManager {
private synchronized void startAll() { private synchronized void startAll() {
final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler(); final IngestScheduler.DataSourceScheduler dataSourceScheduler = scheduler.getDataSourceScheduler();
final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler(); final IngestScheduler.FileScheduler fileScheduler = scheduler.getFileScheduler();
boolean allInited = true;
IngestModuleAbstract failedModule = null;
String errorMessage = "";
logger.log(Level.INFO, "DataSource queue: " + dataSourceScheduler.toString()); logger.log(Level.INFO, "DataSource queue: " + dataSourceScheduler.toString());
logger.log(Level.INFO, "File queue: " + fileScheduler.toString()); logger.log(Level.INFO, "File queue: " + fileScheduler.toString());
@ -299,9 +334,15 @@ public class IngestManager {
ingestMonitor.start(); ingestMonitor.start();
} }
//image ingesters /////////
// Start the data source-level ingest modules
List<IngestDataSourceThread> newThreads = new ArrayList<>();
// cycle through each data source content in the queue // cycle through each data source content in the queue
while (dataSourceScheduler.hasNext()) { while (dataSourceScheduler.hasNext()) {
if (allInited == false) {
break;
}
//dequeue //dequeue
// get next data source content and set of modules // get next data source content and set of modules
final ScheduledTask<IngestModuleDataSource> dataSourceTask = dataSourceScheduler.next(); final ScheduledTask<IngestModuleDataSource> dataSourceTask = dataSourceScheduler.next();
@ -334,14 +375,28 @@ public class IngestManager {
new PipelineContext<IngestModuleDataSource>(dataSourceTask, getProcessUnallocSpace()); new PipelineContext<IngestModuleDataSource>(dataSourceTask, getProcessUnallocSpace());
final IngestDataSourceThread newDataSourceWorker = new IngestDataSourceThread(this, final IngestDataSourceThread newDataSourceWorker = new IngestDataSourceThread(this,
dataSourcepipelineContext, dataSourceTask.getContent(), taskModule, moduleInit); dataSourcepipelineContext, dataSourceTask.getContent(), taskModule, moduleInit);
try {
newDataSourceWorker.init();
} catch (Exception e) {
logger.log(Level.SEVERE, "DataSource ingest module failed init(): " + taskModule.getName(), e);
allInited = false;
failedModule = taskModule;
errorMessage = e.getMessage();
break;
}
dataSourceIngesters.add(newDataSourceWorker); dataSourceIngesters.add(newDataSourceWorker);
// Add the worker to the list of new IngestThreads to be started
// if all modules initialize.
newThreads.add(newDataSourceWorker);
}
}
}
//wrap the module in a worker, that will run init, process and complete on the module // Check to make sure all modules initialized
newDataSourceWorker.execute(); if (allInited == false) {
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), taskModule.getName()); displayInitError(failedModule.getName(), errorMessage);
} dataSourceIngesters.removeAll(newThreads);
} return;
} }
//AbstractFile ingester //AbstractFile ingester
@ -364,19 +419,54 @@ public class IngestManager {
stats = new IngestManagerStats(); stats = new IngestManagerStats();
abstractFileIngester = new IngestAbstractFileProcessor(); abstractFileIngester = new IngestAbstractFileProcessor();
//init all fs modules, everytime new worker starts //init all fs modules, everytime new worker starts
/* @@@ I don't understand why we do an init on each module. Should do only modules
* that we are going to be using in the pipeline
*/
for (IngestModuleAbstractFile s : abstractFileModules) { for (IngestModuleAbstractFile s : abstractFileModules) {
if (fileScheduler.hasModuleEnqueued(s) == false) {
continue;
}
IngestModuleInit moduleInit = new IngestModuleInit(); IngestModuleInit moduleInit = new IngestModuleInit();
try { try {
s.init(moduleInit); s.init(moduleInit);
} catch (Exception e) { } catch (Exception e) {
logger.log(Level.SEVERE, "File ingest module failed init(): " + s.getName()); logger.log(Level.SEVERE, "File ingest module failed init(): " + s.getName(), e);
allInited = false;
failedModule = s;
errorMessage = e.getMessage();
break;
} }
} }
}
if (allInited) {
// Start DataSourceIngestModules
for (IngestDataSourceThread dataSourceWorker : newThreads) {
dataSourceWorker.execute();
IngestManager.fireModuleEvent(IngestModuleEvent.STARTED.toString(), dataSourceWorker.getModule().getName());
}
// Start AbstractFileIngestModules
if (startAbstractFileIngester) {
abstractFileIngester.execute(); abstractFileIngester.execute();
} }
} else {
displayInitError(failedModule.getName(), errorMessage);
dataSourceIngesters.removeAll(newThreads);
abstractFileIngester = null;
}
}
/**
* Open a dialog box to report an initialization error to the user.
*
* @param moduleName The name of the module that failed to initialize.
* @param errorMessage The message gotten from the exception that was thrown.
*/
private void displayInitError(String moduleName, String errorMessage) {
MessageNotifyUtil.Message.error(
"Failed to load " + moduleName + " ingest module.\n\n"
+ "No ingest modules will be run. Please disable the module "
+ "or fix the error and restart ingest by right clicking on "
+ "the data source and selecting Run Ingest Modules.\n\n"
+ "Error: " + errorMessage);
} }
/** /**
@ -930,11 +1020,15 @@ public class IngestManager {
logger.log(Level.SEVERE, "Error: out of memory from module: " + module.getName(), e); logger.log(Level.SEVERE, "Error: out of memory from module: " + module.getName(), e);
stats.addError(module); stats.addError(module);
} }
} //end for every module } //end for every module
//free the internal file resource after done with every module //free the internal file resource after done with every module
fileToProcess.close(); fileToProcess.close();
// notify listeners thsi file is done
fireFileDone(fileToProcess.getId());
int newTotalEnqueuedFiles = fileScheduler.getFilesEnqueuedEst(); int newTotalEnqueuedFiles = fileScheduler.getFilesEnqueuedEst();
if (newTotalEnqueuedFiles > totalEnqueuedFiles) { if (newTotalEnqueuedFiles > totalEnqueuedFiles) {
//update if new enqueued //update if new enqueued
@ -1019,7 +1113,7 @@ public class IngestManager {
} }
} }
/* Thread that adds content/file and module pairs to queues */ /* Thread that adds content/file and module pairs to queues. Starts pipelines when done. */
private class EnqueueWorker extends SwingWorker<Object, Void> { private class EnqueueWorker extends SwingWorker<Object, Void> {
private List<IngestModuleAbstract> modules; private List<IngestModuleAbstract> modules;

View File

@ -60,9 +60,8 @@ import org.sleuthkit.datamodel.TskData.TSK_FS_META_TYPE_ENUM;
* *
*/ */
class IngestScheduler { class IngestScheduler {
private static IngestScheduler instance; private static IngestScheduler instance;
private static Logger logger = Logger.getLogger(IngestScheduler.class.getName()); private static final Logger logger = Logger.getLogger(IngestScheduler.class.getName());
private final DataSourceScheduler dataSourceScheduler = new DataSourceScheduler(); private final DataSourceScheduler dataSourceScheduler = new DataSourceScheduler();
private final FileScheduler fileScheduler = new FileScheduler(); private final FileScheduler fileScheduler = new FileScheduler();
@ -103,12 +102,14 @@ class IngestScheduler {
*/ */
static class FileScheduler implements Iterator<FileScheduler.ProcessTask> { static class FileScheduler implements Iterator<FileScheduler.ProcessTask> {
//root folders enqueued //root folders enqueued
private TreeSet<ProcessTask> rootProcessTasks; private TreeSet<ProcessTask> rootProcessTasks;
//stack of current dirs to be processed recursively //stack of current dirs to be processed recursively
private List<ProcessTask> curDirProcessTasks; private List<ProcessTask> curDirProcessTasks;
//list of files being processed in the currently processed directory //list of files being processed in the currently processed directory
private LinkedList<ProcessTask> curFileProcessTasks; //need to add to start and end quickly private LinkedList<ProcessTask> curFileProcessTasks; //need to add to start and end quickly
//estimated total files to be enqueued for currently scheduled content objects //estimated total files to be enqueued for currently scheduled content objects
private int filesEnqueuedEst; private int filesEnqueuedEst;
private int filesDequeued; private int filesDequeued;
@ -119,9 +120,13 @@ class IngestScheduler {
| TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue(); | TskData.TSK_FS_TYPE_ENUM.TSK_FS_TYPE_NTFS.getValue();
private FileScheduler() { private FileScheduler() {
rootProcessTasks = new TreeSet<ProcessTask>(new RootTaskComparator()); rootProcessTasks = new TreeSet<>(new RootTaskComparator());
curDirProcessTasks = new ArrayList<ProcessTask>(); curDirProcessTasks = new ArrayList<>();
curFileProcessTasks = new LinkedList<ProcessTask>(); curFileProcessTasks = new LinkedList<>();
resetCounters();
}
private void resetCounters() {
filesEnqueuedEst = 0; filesEnqueuedEst = 0;
filesDequeued = 0; filesDequeued = 0;
} }
@ -186,7 +191,7 @@ class IngestScheduler {
} }
/** /**
* Get number of files dequeued so far This is reset after the same * Get number of files dequeued so far. This is reset after the same
* content is enqueued that is already in a queue * content is enqueued that is already in a queue
* *
* @return number of files dequeued so far * @return number of files dequeued so far
@ -269,7 +274,7 @@ class IngestScheduler {
ScheduledTask<IngestModuleAbstractFile> scheduledTask = context.getScheduledTask(); ScheduledTask<IngestModuleAbstractFile> scheduledTask = context.getScheduledTask();
final Content scheduledContent = scheduledTask.getContent(); final Content scheduledContent = scheduledTask.getContent();
Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor()); Collection<AbstractFile> rootObjects = scheduledContent.accept(new GetRootDirVisitor());
List<AbstractFile> firstLevelFiles = new ArrayList<AbstractFile>(); List<AbstractFile> firstLevelFiles = new ArrayList<>();
if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) { if (rootObjects.isEmpty() && scheduledContent instanceof AbstractFile) {
//add the root, which is a leaf itself //add the root, which is a leaf itself
firstLevelFiles.add((AbstractFile) scheduledContent); firstLevelFiles.add((AbstractFile) scheduledContent);
@ -298,7 +303,7 @@ class IngestScheduler {
} }
} }
List<ProcessTask> processTasks = new ArrayList<ProcessTask>(); List<ProcessTask> processTasks = new ArrayList<>();
for (AbstractFile firstLevelFile : firstLevelFiles) { for (AbstractFile firstLevelFile : firstLevelFiles) {
ProcessTask newTask = new ProcessTask(firstLevelFile, context); ProcessTask newTask = new ProcessTask(firstLevelFile, context);
if (shouldEnqueueTask(newTask)) { if (shouldEnqueueTask(newTask)) {
@ -319,7 +324,7 @@ class IngestScheduler {
final Content inputContent = task.getContent(); final Content inputContent = task.getContent();
//remove from root queue //remove from root queue
List<ProcessTask> toRemove = new ArrayList<ProcessTask>(); List<ProcessTask> toRemove = new ArrayList<>();
for (ProcessTask pt : rootProcessTasks) { for (ProcessTask pt : rootProcessTasks) {
if (pt.context.getScheduledTask().getContent().equals(inputContent)) { if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
toRemove.add(pt); toRemove.add(pt);
@ -328,7 +333,7 @@ class IngestScheduler {
rootProcessTasks.removeAll(toRemove); rootProcessTasks.removeAll(toRemove);
//remove from dir stack //remove from dir stack
toRemove = new ArrayList<ProcessTask>(); toRemove = new ArrayList<>();
for (ProcessTask pt : curDirProcessTasks) { for (ProcessTask pt : curDirProcessTasks) {
if (pt.context.getScheduledTask().getContent().equals(inputContent)) { if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
toRemove.add(pt); toRemove.add(pt);
@ -337,7 +342,7 @@ class IngestScheduler {
curDirProcessTasks.removeAll(toRemove); curDirProcessTasks.removeAll(toRemove);
//remove from file queue //remove from file queue
toRemove = new ArrayList<ProcessTask>(); toRemove = new ArrayList<>();
for (ProcessTask pt : curFileProcessTasks) { for (ProcessTask pt : curFileProcessTasks) {
if (pt.context.getScheduledTask().getContent().equals(inputContent)) { if (pt.context.getScheduledTask().getContent().equals(inputContent)) {
toRemove.add(pt); toRemove.add(pt);
@ -419,15 +424,11 @@ class IngestScheduler {
@Override @Override
public synchronized boolean hasNext() { public synchronized boolean hasNext() {
boolean hasNext = !this.curFileProcessTasks.isEmpty(); if (curFileProcessTasks.isEmpty()) {
resetCounters();
if (!hasNext) { return false;
//reset counters
filesDequeued = 0;
filesEnqueuedEst = 0;
} }
return true;
return hasNext;
} }
@Override @Override
@ -438,52 +439,48 @@ class IngestScheduler {
//dequeue the last in the list //dequeue the last in the list
final ProcessTask task = curFileProcessTasks.pollLast(); final ProcessTask task = curFileProcessTasks.pollLast();
filesDequeued++;
//continue shifting to file queue until not empty
while (curFileProcessTasks.isEmpty()
&& !(this.rootProcessTasks.isEmpty() && this.curDirProcessTasks.isEmpty())) {
updateQueues(); updateQueues();
}
++filesDequeued;
return task; return task;
} }
/**
* Shuffle the queues so that there are files in the files queue.
* @returns true if no more data in queue
*/
private synchronized void updateQueues() { private synchronized void updateQueues() {
//if file queue is empty, grab the next one from the dir stack
//if dir stack is empty, grab one from root dir queue first
//when pop from dir stack, get children of popped, and push them back onto stack
if (!this.curFileProcessTasks.isEmpty()) { // we loop because we could have a directory that has all files
// that do not get enqueued
while (true) {
// There are files in the queue, we're done
if (this.curFileProcessTasks.isEmpty() == false) {
return; return;
} }
//no file queue tasks // fill in the directory queue if it is empty.
//grab from dir stack, if available
if (this.curDirProcessTasks.isEmpty()) { if (this.curDirProcessTasks.isEmpty()) {
//grab from root dir sorted queue // bail out if root is also empty -- we are done
if (!rootProcessTasks.isEmpty()) { if (rootProcessTasks.isEmpty()) {
return;
}
ProcessTask rootTask = this.rootProcessTasks.pollFirst(); ProcessTask rootTask = this.rootProcessTasks.pollFirst();
curDirProcessTasks.add(rootTask); curDirProcessTasks.add(rootTask);
} }
}
if (!this.curDirProcessTasks.isEmpty()) {
//pop and push AbstractFile directory children if any //pop and push AbstractFile directory children if any
//add the popped and its leaf children onto cur file list //add the popped and its leaf children onto cur file list
ProcessTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1); ProcessTask parentTask = curDirProcessTasks.remove(curDirProcessTasks.size() - 1);
final AbstractFile parentFile = parentTask.file; final AbstractFile parentFile = parentTask.file;
//add popped to file list
// add itself to the file list
if (shouldEnqueueTask(parentTask)) { if (shouldEnqueueTask(parentTask)) {
this.curFileProcessTasks.addLast(parentTask); this.curFileProcessTasks.addLast(parentTask);
} }
try {
//get children, and if leafs, schedule to file queue
//otherwise push to curDir stack
//TODO use the new more specific method to get list of AbstractFile // add its children to the file and directory lists
try {
List<Content> children = parentFile.getChildren(); List<Content> children = parentFile.getChildren();
for (Content c : children) { for (Content c : children) {
if (c instanceof AbstractFile) { if (c instanceof AbstractFile) {
@ -492,24 +489,17 @@ class IngestScheduler {
if (childFile.isDir()) { if (childFile.isDir()) {
this.curDirProcessTasks.add(childTask); this.curDirProcessTasks.add(childTask);
} else { }
if (shouldEnqueueTask(childTask)) { else if (shouldEnqueueTask(childTask)) {
this.curFileProcessTasks.addLast(childTask); this.curFileProcessTasks.addLast(childTask);
} }
} }
}
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
logger.log(Level.SEVERE, "Could not get children of file and update file queues: " logger.log(Level.SEVERE, "Could not get children of file and update file queues: "
+ parentFile.getName(), ex); + parentFile.getName(), ex);
} }
} }
//logger.info("\nAAA ROOTS " + this.rootProcessTasks);
//logger.info("\nAAA STACK " + this.curDirProcessTasks);
//logger.info("\nAAA CURFILES " + this.curFileProcessTasks);
} }
@Override @Override
@ -518,8 +508,7 @@ class IngestScheduler {
} }
/** /**
* Return list of input source contents associated with the file/dir * Return list of content objects that are in the queue to be processed.
* objects in the queue scheduler to be processed.
* *
* Helpful to determine whether ingest for particular input Content is * Helpful to determine whether ingest for particular input Content is
* active * active
@ -543,6 +532,11 @@ class IngestScheduler {
return new ArrayList<Content>(contentSet); return new ArrayList<Content>(contentSet);
} }
/**
* Determine if a module is in a pipeline in the queue.
* @param module
* @return true if it is in the queue.
*/
synchronized boolean hasModuleEnqueued(IngestModuleAbstractFile module) { synchronized boolean hasModuleEnqueued(IngestModuleAbstractFile module) {
for (ProcessTask task : rootProcessTasks) { for (ProcessTask task : rootProcessTasks) {
for (IngestModuleAbstractFile m : task.context.getScheduledTask().getModules()) { for (IngestModuleAbstractFile m : task.context.getScheduledTask().getModules()) {
@ -578,8 +572,7 @@ class IngestScheduler {
} }
/** /**
* Check if the file meets criteria to be enqueued, or is a special file * Check if the file is a special file that we should skip
* that we should skip
* *
* @param processTask a task whose file to check if should be queued of * @param processTask a task whose file to check if should be queued of
* skipped * skipped
@ -640,7 +633,6 @@ class IngestScheduler {
} }
return true; return true;
} }
@ -702,6 +694,11 @@ class IngestScheduler {
HIGH_PRI_PATHS.add(Pattern.compile("^ProgramData", Pattern.CASE_INSENSITIVE)); HIGH_PRI_PATHS.add(Pattern.compile("^ProgramData", Pattern.CASE_INSENSITIVE));
} }
/**
* Get the scheduling priority for a given file.
* @param abstractFile
* @return
*/
static AbstractFilePriotity.Priority getPriority(final AbstractFile abstractFile) { static AbstractFilePriotity.Priority getPriority(final AbstractFile abstractFile) {
if (!abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) { if (!abstractFile.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.FS)) {
//quickly filter out unstructured content //quickly filter out unstructured content

View File

@ -110,7 +110,8 @@ public class IngestServices {
/** /**
* Fire module data event to notify registered module data event listeners * Fire module data event to notify registered module data event listeners that there
* is new data of a given type from a module
* @param moduleDataEvent module data event, encapsulating blackboard artifact data * @param moduleDataEvent module data event, encapsulating blackboard artifact data
*/ */
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) { public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
@ -120,6 +121,7 @@ public class IngestServices {
/** /**
* Fire module content event to notify registered module content event listeners * Fire module content event to notify registered module content event listeners
* that there is new content (from ZIP file contents, carving, etc.)
* @param moduleContentEvent module content event, encapsulating content changed * @param moduleContentEvent module content event, encapsulating content changed
*/ */
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) { public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {

View File

@ -6,6 +6,7 @@
</Properties> </Properties>
<SyntheticProperties> <SyntheticProperties>
<SyntheticProperty name="formSizePolicy" type="int" value="1"/> <SyntheticProperty name="formSizePolicy" type="int" value="1"/>
<SyntheticProperty name="generateCenter" type="boolean" value="false"/>
</SyntheticProperties> </SyntheticProperties>
<AuxValues> <AuxValues>
<AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/> <AuxValue name="FormSettings_autoResourcing" type="java.lang.Integer" value="1"/>

View File

@ -24,6 +24,8 @@ import java.awt.Toolkit;
import java.awt.event.MouseAdapter; import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent; import java.awt.event.MouseEvent;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.EnumMap; import java.util.EnumMap;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
@ -41,8 +43,6 @@ import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
public class ArtifactSelectionDialog extends javax.swing.JDialog { public class ArtifactSelectionDialog extends javax.swing.JDialog {
private static final Logger logger = Logger.getLogger(ArtifactSelectionDialog.class.getName());
private static ArtifactSelectionDialog instance;
private ArtifactModel model; private ArtifactModel model;
private ArtifactRenderer renderer; private ArtifactRenderer renderer;
@ -66,18 +66,24 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
try { try {
ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotReport = new ArrayList(); ArrayList<BlackboardArtifact.ARTIFACT_TYPE> doNotReport = new ArrayList();
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO); doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_GEN_INFO);
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE); // Obsolete artifact type
doNotReport.add(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT); // Obsolete artifact type
artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse(); artifacts = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifactTypesInUse();
artifacts.removeAll(doNotReport); artifacts.removeAll(doNotReport);
Collections.sort(artifacts, new Comparator<BlackboardArtifact.ARTIFACT_TYPE>() {
@Override
public int compare(ARTIFACT_TYPE o1, ARTIFACT_TYPE o2) {
return o1.getDisplayName().compareTo(o2.getDisplayName());
}
});
artifactStates = new EnumMap<BlackboardArtifact.ARTIFACT_TYPE, Boolean>(BlackboardArtifact.ARTIFACT_TYPE.class); artifactStates = new EnumMap<>(BlackboardArtifact.ARTIFACT_TYPE.class);
for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) { for (BlackboardArtifact.ARTIFACT_TYPE type : artifacts) {
artifactStates.put(type, Boolean.TRUE); artifactStates.put(type, Boolean.TRUE);
} }
} catch (TskCoreException ex) { } catch (TskCoreException ex) {
Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage()); Logger.getLogger(ArtifactSelectionDialog.class.getName()).log(Level.SEVERE, "Error getting list of artifacts in use: " + ex.getLocalizedMessage());
return;
} }
} }
@ -100,27 +106,6 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
}); });
} }
/**
* Returns a list of the artifact types we want to report on.
*/
static List<ARTIFACT_TYPE> getImportantArtifactTypes() {
List<ARTIFACT_TYPE> types = new ArrayList<ARTIFACT_TYPE>();
types.add(ARTIFACT_TYPE.TSK_WEB_BOOKMARK);
types.add(ARTIFACT_TYPE.TSK_WEB_COOKIE);
types.add(ARTIFACT_TYPE.TSK_WEB_HISTORY);
types.add(ARTIFACT_TYPE.TSK_WEB_DOWNLOAD);
types.add(ARTIFACT_TYPE.TSK_RECENT_OBJECT);
types.add(ARTIFACT_TYPE.TSK_INSTALLED_PROG);
types.add(ARTIFACT_TYPE.TSK_KEYWORD_HIT);
types.add(ARTIFACT_TYPE.TSK_HASHSET_HIT);
types.add(ARTIFACT_TYPE.TSK_DEVICE_ATTACHED);
types.add(ARTIFACT_TYPE.TSK_WEB_SEARCH_QUERY);
types.add(ARTIFACT_TYPE.TSK_METADATA_EXIF);
types.add(ARTIFACT_TYPE.TSK_TAG_FILE);
types.add(ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
return types;
}
/** /**
* Display this dialog, and return the selected artifacts. * Display this dialog, and return the selected artifacts.
*/ */
@ -288,7 +273,5 @@ public class ArtifactSelectionDialog extends javax.swing.JDialog {
} }
return new JLabel(); return new JLabel();
} }
} }
} }

View File

@ -30,3 +30,13 @@ ReportProgressPanel.processingLabel.text=processingLabel
ReportGenerationPanel.titleLabel.text=Report Generation Progress ReportGenerationPanel.titleLabel.text=Report Generation Progress
ReportVisualPanel2.taggedResultsRadioButton.text=Tagged Results ReportVisualPanel2.taggedResultsRadioButton.text=Tagged Results
ReportVisualPanel2.allResultsRadioButton.text=All Results ReportVisualPanel2.allResultsRadioButton.text=All Results
FileReportConfigurationPanel.jLabel1.text=Select Items to Report:
FileReportConfigurationPanel.selectAllButton.text=Select All
FileReportConfigurationPanel.deselectAllButton.text=Deselect All
FileReportConfigurationDialog.selectAllButton.text=Select All
FileReportConfigurationDialog.deselectAllButton.text=Deselect All
FileReportConfigurationDialog.jLabel1.text=Select items to include in the File Report
FileReportConfigurationDialog.okButton.text=OK
ReportWizardFileOptionsVisualPanel.selectAllButton.text=Select All
ReportWizardFileOptionsVisualPanel.deselectAllButton.text=Deselect All
ReportWizardFileOptionsVisualPanel.jLabel1.text=Select items to include in File Report:

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

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

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

View File

@ -161,7 +161,7 @@ public class ReportBodyFile implements GeneralReportModule {
@Override @Override
public String getName() { public String getName() {
String name = "Body File"; String name = "TSK Body File";
return name; return name;
} }

View File

@ -121,40 +121,6 @@ public class ReportExcel implements TableReportModule {
} }
} }
/**
* Start a new worksheet for the given data type.
* @param name data type name
*/
@Override
public void startDataType(String name) {
// Create a worksheet for the data type (assumed to be an artifact type).
name = escapeForExcel(name);
sheet = wb.createSheet(name);
sheet.setAutobreaks(true);
rowIndex = 0;
artifactsCount = 0;
// Add a title row to the worksheet.
Row row = sheet.createRow(rowIndex);
row.setRowStyle(setStyle);
row.createCell(0).setCellValue(name);
++rowIndex;
// Add an artifacts count row. The actual count will be filled in later.
row = sheet.createRow(rowIndex);
row.setRowStyle(setStyle);
row.createCell(0).setCellValue("Number of artifacts:");
++rowIndex;
// Add an empty row as a separator.
sheet.createRow(rowIndex);
++rowIndex;
// There will be at least two columns, one each for the artifacts count and its label.
sheetColCount = 2;
}
/** /**
* Start a new worksheet for the given data type. * Start a new worksheet for the given data type.
* Note: This method is a temporary workaround to avoid modifying the TableReportModule interface. * Note: This method is a temporary workaround to avoid modifying the TableReportModule interface.
@ -162,7 +128,8 @@ public class ReportExcel implements TableReportModule {
* @param name Name of the data type * @param name Name of the data type
* @param comment Comment on the data type, may be the empty string * @param comment Comment on the data type, may be the empty string
*/ */
public void startDataType(String name, String comment) { @Override
public void startDataType(String name, String description) {
// Create a worksheet for the data type (assumed to be an artifact type). // Create a worksheet for the data type (assumed to be an artifact type).
name = escapeForExcel(name); name = escapeForExcel(name);
sheet = wb.createSheet(name); sheet = wb.createSheet(name);
@ -183,10 +150,10 @@ public class ReportExcel implements TableReportModule {
++rowIndex; ++rowIndex;
// Add a comment row, if a comment was supplied. // Add a comment row, if a comment was supplied.
if (!comment.isEmpty()) { if (!description.isEmpty()) {
row = sheet.createRow(rowIndex); row = sheet.createRow(rowIndex);
row.setRowStyle(setStyle); row.setRowStyle(setStyle);
row.createCell(0).setCellValue(comment); row.createCell(0).setCellValue(description);
++rowIndex; ++rowIndex;
} }
@ -310,7 +277,7 @@ public class ReportExcel implements TableReportModule {
@Override @Override
public String getName() { public String getName() {
return "Excel"; return "Results - Excel";
} }
@Override @Override

File diff suppressed because it is too large Load Diff

View File

@ -28,7 +28,6 @@ import java.io.FileNotFoundException;
import java.io.FileOutputStream; import java.io.FileOutputStream;
import java.io.IOException; import java.io.IOException;
import java.io.InputStream; import java.io.InputStream;
import java.io.FileInputStream;
import java.io.OutputStream; import java.io.OutputStream;
import java.io.OutputStreamWriter; import java.io.OutputStreamWriter;
import java.io.UnsupportedEncodingException; import java.io.UnsupportedEncodingException;
@ -36,7 +35,6 @@ import java.io.Writer;
import java.text.DateFormat; import java.text.DateFormat;
import java.text.SimpleDateFormat; import java.text.SimpleDateFormat;
import java.util.Date; import java.util.Date;
import java.util.HashSet;
import java.util.List; import java.util.List;
import java.util.Map; import java.util.Map;
import java.util.TreeMap; import java.util.TreeMap;
@ -45,17 +43,15 @@ import org.openide.filesystems.FileUtil;
import org.openide.util.Exceptions; import org.openide.util.Exceptions;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.Tags;
import org.sleuthkit.autopsy.datamodel.ContentUtils;
import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor; import org.sleuthkit.autopsy.datamodel.ContentUtils.ExtractFscContentVisitor;
import org.sleuthkit.autopsy.ingest.IngestManager; import org.sleuthkit.autopsy.ingest.IngestManager;
import org.sleuthkit.datamodel.AbstractFile;
import org.sleuthkit.datamodel.Image; import org.sleuthkit.datamodel.Image;
import org.sleuthkit.datamodel.SleuthkitCase; import org.sleuthkit.datamodel.SleuthkitCase;
import org.sleuthkit.datamodel.TskCoreException; import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.AbstractFile; import org.sleuthkit.datamodel.ContentTag;
import org.sleuthkit.datamodel.TskData;
import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM; import org.sleuthkit.datamodel.TskData.TSK_DB_FILES_TYPE_ENUM;
public class ReportHTML implements TableReportModule { public class ReportHTML implements TableReportModule {
@ -91,7 +87,7 @@ public class ReportHTML implements TableReportModule {
currentCase = Case.getCurrentCase(); currentCase = Case.getCurrentCase();
skCase = currentCase.getSleuthkitCase(); skCase = currentCase.getSleuthkitCase();
dataTypes = new TreeMap<String, Integer>(); dataTypes = new TreeMap<>();
path = ""; path = "";
currentDataType = ""; currentDataType = "";
@ -129,10 +125,10 @@ public class ReportHTML implements TableReportModule {
{ {
String iconFilePath; String iconFilePath;
String iconFileName; String iconFileName;
InputStream in = null; InputStream in;
OutputStream output = null; OutputStream output = null;
logger.log(Level.INFO, "useDataTypeIcon: dataType = " + dataType); logger.log(Level.INFO, "useDataTypeIcon: dataType = {0}", dataType);
// find the artifact with matching display name // find the artifact with matching display name
BlackboardArtifact.ARTIFACT_TYPE artifactType = null; BlackboardArtifact.ARTIFACT_TYPE artifactType = null;
@ -297,39 +293,6 @@ public class ReportHTML implements TableReportModule {
} }
} }
/**
* Start a new HTML page for the given data type. Update the output stream to this page,
* and setup the web page header.
* @param title title of the data type
*/
@Override
public void startDataType(String title) {
String fTitle = dataTypeToFileName(title);
// Make a new out for this page
try {
//escape out slashes tha that appear in title
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + fTitle + getExtension()), "UTF-8"));
} catch (FileNotFoundException ex) {
logger.log(Level.SEVERE, "File not found: {0}", ex);
} catch (UnsupportedEncodingException ex) {
logger.log(Level.SEVERE, "Unrecognized encoding");
}
// Write the beginnings of a page
// Like <html>, header, title, any content divs
try {
StringBuilder page = new StringBuilder();
page.append("<html>\n<head>\n\t<title>").append(title).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n");
page.append("<div id=\"header\">").append(title).append("</div>\n<div id=\"content\">\n");
out.write(page.toString());
currentDataType = title;
rowCount = 0;
} catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write page head: {0}", ex);
}
}
/** /**
* Start a new HTML page for the given data type. Update the output stream to this page, * Start a new HTML page for the given data type. Update the output stream to this page,
* and setup the web page header. * and setup the web page header.
@ -338,7 +301,8 @@ public class ReportHTML implements TableReportModule {
* @param name Name of the data type * @param name Name of the data type
* @param comment Comment on the data type, may be the empty string * @param comment Comment on the data type, may be the empty string
*/ */
public void startDataType(String name, String comment) { @Override
public void startDataType(String name, String description) {
String title = dataTypeToFileName(name); String title = dataTypeToFileName(name);
try { try {
out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8")); out = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(path + title + getExtension()), "UTF-8"));
@ -352,9 +316,9 @@ public class ReportHTML implements TableReportModule {
StringBuilder page = new StringBuilder(); StringBuilder page = new StringBuilder();
page.append("<html>\n<head>\n\t<title>").append(name).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n"); page.append("<html>\n<head>\n\t<title>").append(name).append("</title>\n\t<link rel=\"stylesheet\" type=\"text/css\" href=\"index.css\" />\n<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n</head>\n<body>\n");
page.append("<div id=\"header\">").append(name).append("</div>\n<div id=\"content\">\n"); page.append("<div id=\"header\">").append(name).append("</div>\n<div id=\"content\">\n");
if (!comment.isEmpty()) { if (!description.isEmpty()) {
page.append("<p><strong>"); page.append("<p><strong>");
page.append(comment); page.append(description);
page.append("</string></p>\n"); page.append("</string></p>\n");
} }
out.write(page.toString()); out.write(page.toString());
@ -477,17 +441,17 @@ public class ReportHTML implements TableReportModule {
* @param columnHeaders column headers * @param columnHeaders column headers
* @param sourceArtifact source blackboard artifact for the table data * @param sourceArtifact source blackboard artifact for the table data
*/ */
public void startTable(List<String> columnHeaders, ARTIFACT_TYPE artifactType) { public void startContentTagsTable(List<String> columnHeaders) {
StringBuilder htmlOutput = new StringBuilder(); StringBuilder htmlOutput = new StringBuilder();
htmlOutput.append("<table>\n<thead>\n\t<tr>\n"); htmlOutput.append("<table>\n<thead>\n\t<tr>\n");
// Add the specified columns.
for(String columnHeader : columnHeaders) { for(String columnHeader : columnHeaders) {
htmlOutput.append("\t\t<th>").append(columnHeader).append("</th>\n"); htmlOutput.append("\t\t<th>").append(columnHeader).append("</th>\n");
} }
// For file tag artifacts, add a column for a hyperlink to a local copy of the tagged file. // Add a column for a hyperlink to a local copy of the tagged content.
if (artifactType.equals(ARTIFACT_TYPE.TSK_TAG_FILE)) {
htmlOutput.append("\t\t<th></th>\n"); htmlOutput.append("\t\t<th></th>\n");
}
htmlOutput.append("\t</tr>\n</thead>\n"); htmlOutput.append("\t</tr>\n</thead>\n");
@ -527,68 +491,29 @@ public class ReportHTML implements TableReportModule {
try { try {
out.write(builder.toString()); out.write(builder.toString());
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write row to out.");
} catch (NullPointerException ex) {
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.");
}
}
/**
* Add a row to the current table.
*
* @param row values for each cell in the row
* @param sourceArtifact source blackboard artifact for the table data
*/
public void addRow(List<String> row, BlackboardArtifact sourceArtifact) {
addRowDataForSourceArtifact(row, sourceArtifact);
StringBuilder builder = new StringBuilder();
builder.append("\t<tr>\n");
for (String cell : row) {
builder.append("\t\t<td>").append(cell).append("</td>\n");
}
builder.append("\t</tr>\n");
rowCount++;
try {
out.write(builder.toString());
}
catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write row to out.", ex); logger.log(Level.SEVERE, "Failed to write row to out.", ex);
} } catch (NullPointerException ex) {
catch (NullPointerException ex) {
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex); logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
} }
} }
/** /**
* Add cells particular to a type of artifact associated with the row. Assumes that the overload of startTable() that takes an artifact type was called. * Saves a local copy of a tagged file and adds a row with a hyper link to
* the file.
* *
* @param row The row. * @param row Values for each data cell in the row.
* @param sourceArtifact The artifact associated with the row. * @param contentTag A content tag to use to make the hyper link.
*/ */
private void addRowDataForSourceArtifact(List<String> row, BlackboardArtifact sourceArtifact) { public void addRowWithTaggedContentHyperlink(List<String> row, ContentTag contentTag) {
int artifactTypeID = sourceArtifact.getArtifactTypeID(); // Only handling AbstractFiles at present.
BlackboardArtifact.ARTIFACT_TYPE type = BlackboardArtifact.ARTIFACT_TYPE.fromID(artifactTypeID); AbstractFile file;
switch (type) { if (contentTag.getContent() instanceof AbstractFile) {
case TSK_TAG_FILE: file = (AbstractFile)contentTag.getContent();
addRowDataForFileTagArtifact(row, sourceArtifact);
break;
default:
break;
} }
else {
return;
} }
/**
* Saves a local copy of a tagged file and adds a hyper link to the file to the row.
*
* @param row The row.
* @param sourceArtifact The artifact associated with the row.
*/
private void addRowDataForFileTagArtifact(List<String> row, BlackboardArtifact sourceArtifact) {
try {
AbstractFile file = Case.getCurrentCase().getSleuthkitCase().getAbstractFileById(sourceArtifact.getObjectID());
// Don't make a local copy of the file if it is a directory or unallocated space. // Don't make a local copy of the file if it is a directory or unallocated space.
if (file.isDir() || if (file.isDir() ||
file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS || file.getType() == TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS ||
@ -600,18 +525,15 @@ public class ReportHTML implements TableReportModule {
// Make a folder for the local file with the same name as the tag. // Make a folder for the local file with the same name as the tag.
StringBuilder localFilePath = new StringBuilder(); StringBuilder localFilePath = new StringBuilder();
localFilePath.append(path); localFilePath.append(path);
HashSet<String> tagNames = Tags.getUniqueTagNamesForArtifact(sourceArtifact); localFilePath.append(contentTag.getName().getDisplayName());
if (!tagNames.isEmpty()) {
localFilePath.append(tagNames.iterator().next());
}
File localFileFolder = new File(localFilePath.toString()); File localFileFolder = new File(localFilePath.toString());
if (!localFileFolder.exists()) { if (!localFileFolder.exists()) {
localFileFolder.mkdirs(); localFileFolder.mkdirs();
} }
// Construct a file name for the local file that incorporates the corresponding object id to ensure uniqueness. // Construct a file name for the local file that incorporates the file id to ensure uniqueness.
String fileName = file.getName(); String fileName = file.getName();
String objectIdSuffix = "_" + sourceArtifact.getObjectID(); String objectIdSuffix = "_" + file.getId();
int lastDotIndex = fileName.lastIndexOf("."); int lastDotIndex = fileName.lastIndexOf(".");
if (lastDotIndex != -1 && lastDotIndex != 0) { if (lastDotIndex != -1 && lastDotIndex != 0) {
// The file name has a conventional extension. Insert the object id before the '.' of the extension. // The file name has a conventional extension. Insert the object id before the '.' of the extension.
@ -638,10 +560,23 @@ public class ReportHTML implements TableReportModule {
localFileLink.append(localFilePath.toString()); localFileLink.append(localFilePath.toString());
localFileLink.append("\">View File</a>"); localFileLink.append("\">View File</a>");
row.add(localFileLink.toString()); row.add(localFileLink.toString());
StringBuilder builder = new StringBuilder();
builder.append("\t<tr>\n");
for (String cell : row) {
builder.append("\t\t<td>").append(cell).append("</td>\n");
} }
catch (TskCoreException ex) { builder.append("\t</tr>\n");
logger.log(Level.WARNING, "Failed to get AbstractFile by ID.", ex); rowCount++;
row.add("");
try {
out.write(builder.toString());
}
catch (IOException ex) {
logger.log(Level.SEVERE, "Failed to write row to out.", ex);
}
catch (NullPointerException ex) {
logger.log(Level.SEVERE, "Output writer is null. Page was not initialized before writing.", ex);
} }
} }
@ -665,7 +600,7 @@ public class ReportHTML implements TableReportModule {
@Override @Override
public String getName() { public String getName() {
return "HTML"; return "Results - HTML";
} }
@Override @Override
@ -704,11 +639,11 @@ public class ReportHTML implements TableReportModule {
"table tr:nth-child(even) td {background: #f3f3f3;}"; "table tr:nth-child(even) td {background: #f3f3f3;}";
cssOut.write(css); cssOut.write(css);
} catch (FileNotFoundException ex) { } catch (FileNotFoundException ex) {
logger.log(Level.SEVERE, "Could not find index.css file to write to."); logger.log(Level.SEVERE, "Could not find index.css file to write to.", ex);
} catch (UnsupportedEncodingException ex) { } catch (UnsupportedEncodingException ex) {
logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css."); logger.log(Level.SEVERE, "Did not recognize encoding when writing index.css.", ex);
} catch (IOException ex) { } catch (IOException ex) {
logger.log(Level.SEVERE, "Error creating Writer for index.css."); logger.log(Level.SEVERE, "Error creating Writer for index.css.", ex);
} finally { } finally {
try { try {
if(cssOut != null) { if(cssOut != null) {

View File

@ -23,37 +23,30 @@
package org.sleuthkit.autopsy.report; package org.sleuthkit.autopsy.report;
/** /**
* Interface extended by TableReportModule and GeneralReportModule. * Interface got report modules that plug in to the reporting infrastructure.
* Contains vital report information to be used by every report.
*/ */
public interface ReportModule { public interface ReportModule {
/** /**
* Returns a basic string name for the report. What is 'officially' titled. * Get the name of the report this module generates.
*
* @return the report name
*/ */
public String getName(); public String getName();
/** /**
* Returns a one line user friendly description of the type of report this * Gets a one-line, user friendly description of the type of report this
* module generates * module generates.
* @return user-friendly report description
*/ */
public String getDescription(); public String getDescription();
/** /**
* Returns the extension that is used for the report * Gets the extension of the report file, if any, generated by this module.
* * @return File name extension, may be null.
* @return String the extension the file will be saved as
*
*/ */
public String getExtension(); public String getExtension();
/** /**
* Returns the path to the main (or only) file for the report. * Gets the path of the report file, if any, generated by this module.
* * @return File path, may be null.
* @return String path to the report file
*/ */
public String getFilePath(); public String getFilePath();
} }

View File

@ -48,16 +48,17 @@ public class ReportProgressPanel extends javax.swing.JPanel {
} }
private void customInit(String reportName, String reportPath) { private void customInit(String reportName, String reportPath) {
reportLabel.setText(reportName);
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
pathLabel.setToolTipText(reportPath);
reportProgressBar.setIndeterminate(true); reportProgressBar.setIndeterminate(true);
reportProgressBar.setMaximum(100); reportProgressBar.setMaximum(100);
reportLabel.setText(reportName);
processingLabel.setText("Queuing..."); processingLabel.setText("Queuing...");
STATUS = ReportStatus.QUEUING; STATUS = ReportStatus.QUEUING;
if (reportPath != null) {
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
pathLabel.setToolTipText(reportPath);
// Add the "link" effect to the pathLabel // Add the "link" effect to the pathLabel
final String linkPath = reportPath; final String linkPath = reportPath;
pathLabel.addMouseListener(new MouseListener() { pathLabel.addMouseListener(new MouseListener() {
@ -99,6 +100,10 @@ public class ReportProgressPanel extends javax.swing.JPanel {
}); });
} }
else {
pathLabel.setText("<html><u>No report file</u></html>");
}
}
/** /**
* Return a shortened version of the given path. * Return a shortened version of the given path.

Some files were not shown because too many files have changed in this diff Show More