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.
- DataContentViewer.isPreferred does not need isSupported to be passed in
- DataContentViewerHex and STrings can have the public setDataView methods removed in favor of the new private ones
Content.getUniquePath() shoudl not thrown TskException. We should deal with it in the method.
- DataContentViewerHex and Strings can have the public setDataView methods removed in favor of the new private ones
- Content.getUniquePath() should not thrown TskException. We should deal with it in the method.
- Make the list of events that Case fires off to be part of an enum to group them together (like IngestManager does).
- Sub-modules in RecentActivity have a bunch of public/protected variables that do not need to be. (i.e. ExtractRegistry.rrFullFound).
- Delete BrowserType enum and BrowserActivityType in RecentActivity.

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
*

View File

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

View File

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

View File

@ -52,165 +52,168 @@ public class JLnkParser {
}
}
public JLNK parse() {
ByteBuffer bb = ByteBuffer.wrap(content);
bb.order(ByteOrder.LITTLE_ENDIAN);
int header = bb.getInt();
ByteBuffer linkClassIdentifier = bb.get(new byte[16]);
int linkFlags = bb.getInt();
int fileAttributes = bb.getInt();
long crtime = bb.getLong();
long atime = bb.getLong();
long mtime = bb.getLong();
int fileSize = bb.getInt();
int iconIndex = bb.getInt();
int showCommand = bb.getInt();
short hotkey = bb.getShort();
bb.get(new byte[10]); // reserved (???)
List<String> linkTargetIdList = new ArrayList<String>();
if((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) ==
LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) {
int idListSize = bb.getShort();
int bytesRead = 0;
List<byte[]> linkTargetIdListBytes = new ArrayList<byte[]>();
while(true) {
short itemIdSize = bb.getShort();
if(itemIdSize == 0) {
bytesRead += 2; // two null bytes to terminate id list
break;
public JLNK parse() throws JLnkParserException {
try {
ByteBuffer bb = ByteBuffer.wrap(content);
bb.order(ByteOrder.LITTLE_ENDIAN);
int header = bb.getInt();
ByteBuffer linkClassIdentifier = bb.get(new byte[16]);
int linkFlags = bb.getInt();
int fileAttributes = bb.getInt();
long crtime = bb.getLong();
long atime = bb.getLong();
long mtime = bb.getLong();
int fileSize = bb.getInt();
int iconIndex = bb.getInt();
int showCommand = bb.getInt();
short hotkey = bb.getShort();
bb.get(new byte[10]); // reserved (???)
List<String> linkTargetIdList = new ArrayList<String>();
if((linkFlags & LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) ==
LnkEnums.LinkFlags.HasLinkTargetIDList.getFlag()) {
int idListSize = bb.getShort();
int bytesRead = 0;
List<byte[]> linkTargetIdListBytes = new ArrayList<byte[]>();
while(true) {
short itemIdSize = bb.getShort();
if(itemIdSize == 0) {
bytesRead += 2; // two null bytes to terminate id list
break;
}
byte[] theArray = new byte[itemIdSize-2];
bb.get(theArray); // an idlist data object
linkTargetIdListBytes.add(theArray);
bytesRead = bytesRead + itemIdSize;
}
byte[] theArray = new byte[itemIdSize-2];
bb.get(theArray); // an idlist data object
linkTargetIdListBytes.add(theArray);
bytesRead = bytesRead + itemIdSize;
linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes);
}
linkTargetIdList = parseLinkTargetIdList(linkTargetIdListBytes);
}
boolean hasUnicodeLocalBaseAndCommonSuffixOffset = false;
String localBasePath = null;
String commonPathSuffix = null;
String localBasePathUnicode = null;
String commonPathSuffixUnicode = null;
int driveSerialNumber = -1;
DriveType driveType = null;
String volumeLabel = null;
int commonNetworkRelativeLinkFlags = -1;
NetworkProviderType networkProviderType = null;
boolean unicodeNetAndDeviceName = false;
String netName = null;
String netNameUnicode = null;
String deviceName = null;
String deviceNameUnicode = null;
boolean hasUnicodeLocalBaseAndCommonSuffixOffset = false;
String localBasePath = null;
String commonPathSuffix = null;
String localBasePathUnicode = null;
String commonPathSuffixUnicode = null;
int driveSerialNumber = -1;
DriveType driveType = null;
String volumeLabel = null;
int commonNetworkRelativeLinkFlags = -1;
NetworkProviderType networkProviderType = null;
boolean unicodeNetAndDeviceName = false;
String netName = null;
String netNameUnicode = null;
String deviceName = null;
String deviceNameUnicode = null;
if((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) ==
LnkEnums.LinkFlags.HasLinkInfo.getFlag()) {
int startOfLinkInfo = bb.position();
int linkInfoSize = bb.getInt();
int linkInfoHeaderSize = bb.getInt();
hasUnicodeLocalBaseAndCommonSuffixOffset = linkInfoHeaderSize >= 0x24;
int linkInfoFlags = bb.getInt();
int volumeIdOffset = bb.getInt();
int localBasePathOffset = bb.getInt();
int commonNetworkRelativeLinkOffset = bb.getInt();
int commonPathSuffixOffset = bb.getInt();
int localBasePathOffsetUnicode = 0;
int commonPathSuffixOffsetUnicode = 0;
if (hasUnicodeLocalBaseAndCommonSuffixOffset) {
localBasePathOffsetUnicode = bb.getInt();
commonPathSuffixOffsetUnicode = bb.getInt();
}
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) {
bb.position(startOfLinkInfo+volumeIdOffset);
int volumeIdSize = bb.getInt();
driveType = DriveType.valueOf(bb.getInt());
driveSerialNumber = bb.getInt();
int volumeLabelOffset = bb.getInt();
if (volumeLabelOffset != 0x14) {
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffset, false, volumeIdSize - 0x10);
} else {
int volumeLabelOffsetUnicode = bb.getInt();
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffsetUnicode, false, volumeIdSize - 0x14);
if((linkFlags & LnkEnums.LinkFlags.HasLinkInfo.getFlag()) ==
LnkEnums.LinkFlags.HasLinkInfo.getFlag()) {
int startOfLinkInfo = bb.position();
int linkInfoSize = bb.getInt();
int linkInfoHeaderSize = bb.getInt();
hasUnicodeLocalBaseAndCommonSuffixOffset = linkInfoHeaderSize >= 0x24;
int linkInfoFlags = bb.getInt();
int volumeIdOffset = bb.getInt();
int localBasePathOffset = bb.getInt();
int commonNetworkRelativeLinkOffset = bb.getInt();
int commonPathSuffixOffset = bb.getInt();
int localBasePathOffsetUnicode = 0;
int commonPathSuffixOffsetUnicode = 0;
if (hasUnicodeLocalBaseAndCommonSuffixOffset) {
localBasePathOffsetUnicode = bb.getInt();
commonPathSuffixOffsetUnicode = bb.getInt();
}
localBasePath = parseLocalBasePath(startOfLinkInfo + localBasePathOffset, false);
}
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag())
== LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) {
bb.position(startOfLinkInfo+commonNetworkRelativeLinkOffset);
int commonNetworkRelativeLinkSize = bb.getInt();
commonNetworkRelativeLinkFlags = bb.getInt();
int netNameOffset = bb.getInt();
unicodeNetAndDeviceName = netNameOffset > 0x14;
int deviceNameOffset = bb.getInt();
int netType = bb.getInt();
int netNameOffsetUnicode = 0;
int deviceNameOffsetUnicode = 0;
if (unicodeNetAndDeviceName) {
netNameOffsetUnicode = bb.getInt();
deviceNameOffsetUnicode = bb.getInt();
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag()) {
bb.position(startOfLinkInfo+volumeIdOffset);
int volumeIdSize = bb.getInt();
driveType = DriveType.valueOf(bb.getInt());
driveSerialNumber = bb.getInt();
int volumeLabelOffset = bb.getInt();
if (volumeLabelOffset != 0x14) {
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffset, false, volumeIdSize - 0x10);
} else {
int volumeLabelOffsetUnicode = bb.getInt();
volumeLabel = parseString(startOfLinkInfo + volumeIdOffset + volumeLabelOffsetUnicode, false, volumeIdSize - 0x14);
}
localBasePath = parseLocalBasePath(startOfLinkInfo + localBasePathOffset, false);
}
netName = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffset, false);
if (unicodeNetAndDeviceName) {
netNameUnicode = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffsetUnicode, true);
}
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag())
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag()) {
networkProviderType = LnkEnums.NetworkProviderType.valueOf(netType);
}
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag())
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag()) {
deviceName = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffset, false);
if ((linkInfoFlags & LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag())
== LnkEnums.LinkInfoFlags.CommonNetworkRelativeLinkAndPathSuffix.getFlag()) {
bb.position(startOfLinkInfo+commonNetworkRelativeLinkOffset);
int commonNetworkRelativeLinkSize = bb.getInt();
commonNetworkRelativeLinkFlags = bb.getInt();
int netNameOffset = bb.getInt();
unicodeNetAndDeviceName = netNameOffset > 0x14;
int deviceNameOffset = bb.getInt();
int netType = bb.getInt();
int netNameOffsetUnicode = 0;
int deviceNameOffsetUnicode = 0;
if (unicodeNetAndDeviceName) {
deviceNameUnicode = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffsetUnicode, true);
netNameOffsetUnicode = bb.getInt();
deviceNameOffsetUnicode = bb.getInt();
}
netName = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffset, false);
if (unicodeNetAndDeviceName) {
netNameUnicode = parseNetName(startOfLinkInfo + commonNetworkRelativeLinkOffset + netNameOffsetUnicode, true);
}
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag())
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidNetType.getFlag()) {
networkProviderType = LnkEnums.NetworkProviderType.valueOf(netType);
}
if ((commonNetworkRelativeLinkFlags & LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag())
== LnkEnums.CommonNetworkRelativeLinkFlags.ValidDevice.getFlag()) {
deviceName = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffset, false);
if (unicodeNetAndDeviceName) {
deviceNameUnicode = parseDeviceName(startOfLinkInfo + commonNetworkRelativeLinkOffset + deviceNameOffsetUnicode, true);
}
}
}
commonPathSuffix = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffset, false);
if (((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
&& hasUnicodeLocalBaseAndCommonSuffixOffset) {
localBasePathUnicode = parseLocalBasePath(startOfLinkInfo + localBasePathOffsetUnicode, true);
commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true);
}
bb.position(startOfLinkInfo+linkInfoSize);
}
commonPathSuffix = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffset, false);
if (((linkInfoFlags & LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
== LnkEnums.LinkInfoFlags.VolumeIDAndLocalBasePath.getFlag())
&& hasUnicodeLocalBaseAndCommonSuffixOffset) {
localBasePathUnicode = parseLocalBasePath(startOfLinkInfo + localBasePathOffsetUnicode, true);
commonPathSuffixUnicode = parseCommonPathSuffix(startOfLinkInfo + commonPathSuffixOffsetUnicode, true);
String name = null;
if((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) ==
LnkEnums.LinkFlags.HasName.getFlag()) {
name = readStringData(bb);
}
String relativePath = null;
if((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) ==
LnkEnums.LinkFlags.HasRelativePath.getFlag()) {
relativePath = readStringData(bb);
}
String workingDir = null;
if((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) ==
LnkEnums.LinkFlags.HasWorkingDir.getFlag()) {
workingDir = readStringData(bb);
}
String arguments = null;
if((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) ==
LnkEnums.LinkFlags.HasArguments.getFlag()) {
arguments = readStringData(bb);
}
String iconLocation = null;
if((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) ==
LnkEnums.LinkFlags.HasIconLocation.getFlag()) {
iconLocation = readStringData(bb);
}
bb.position(startOfLinkInfo+linkInfoSize);
return new JLNK(header, linkClassIdentifier.array(), linkFlags, fileAttributes,
crtime, atime, mtime, fileSize, iconIndex, showCommand, hotkey,
linkTargetIdList,
hasUnicodeLocalBaseAndCommonSuffixOffset, localBasePath,
commonPathSuffix, localBasePathUnicode, commonPathSuffixUnicode,
name, relativePath, workingDir, arguments, iconLocation, driveSerialNumber,
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
deviceName, deviceNameUnicode);
} catch (Exception e) {
throw new JLnkParserException(e);
}
String name = null;
if((linkFlags & LnkEnums.LinkFlags.HasName.getFlag()) ==
LnkEnums.LinkFlags.HasName.getFlag()) {
name = readStringData(bb);
}
String relativePath = null;
if((linkFlags & LnkEnums.LinkFlags.HasRelativePath.getFlag()) ==
LnkEnums.LinkFlags.HasRelativePath.getFlag()) {
relativePath = readStringData(bb);
}
String workingDir = null;
if((linkFlags & LnkEnums.LinkFlags.HasWorkingDir.getFlag()) ==
LnkEnums.LinkFlags.HasWorkingDir.getFlag()) {
workingDir = readStringData(bb);
}
String arguments = null;
if((linkFlags & LnkEnums.LinkFlags.HasArguments.getFlag()) ==
LnkEnums.LinkFlags.HasArguments.getFlag()) {
arguments = readStringData(bb);
}
String iconLocation = null;
if((linkFlags & LnkEnums.LinkFlags.HasIconLocation.getFlag()) ==
LnkEnums.LinkFlags.HasIconLocation.getFlag()) {
iconLocation = readStringData(bb);
}
return new JLNK(header, linkClassIdentifier.array(), linkFlags, fileAttributes,
crtime, atime, mtime, fileSize, iconIndex, showCommand, hotkey,
linkTargetIdList,
hasUnicodeLocalBaseAndCommonSuffixOffset, localBasePath,
commonPathSuffix, localBasePathUnicode, commonPathSuffixUnicode,
name, relativePath, workingDir, arguments, iconLocation, driveSerialNumber,
driveType, volumeLabel, commonNetworkRelativeLinkFlags,
networkProviderType, unicodeNetAndDeviceName, netName, netNameUnicode,
deviceName, deviceNameUnicode);
}
private String readStringData(ByteBuffer bb) {
@ -337,3 +340,5 @@ public class JLnkParser {
return new String(nameArr).split("\0")[0];
}
}

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

View File

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

View File

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

View File

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

View File

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

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
public TYPE getDisplayableItemNodeType() {
return TYPE.CONTENT;
public boolean isLeafTypeNode() {
return false;
}
@Override

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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
public <T> T accept(AutopsyItemVisitor<T> v) {
return v.visit(this);
@ -113,8 +150,8 @@ public class HashsetHits implements AutopsyVisitableItem {
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
public boolean isLeafTypeNode() {
return false;
}
@Override
@ -163,11 +200,6 @@ public class HashsetHits implements AutopsyVisitableItem {
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/hashset_hits.png");
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.ARTIFACT;
}
@Override
public boolean isLeafTypeNode() {
return true;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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");
}
@Override
public boolean isLeafTypeNode() {
return false;
}
@Override
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
return v.visit(this);
@ -65,9 +70,4 @@ public class ViewsNode extends DisplayableItemNode {
NAME));
return s;
}
@Override
public TYPE getDisplayableItemNodeType() {
return TYPE.META;
}
}

View File

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

View File

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

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=...
DirectoryTreeTopComponent.backButton.text=
DirectoryTreeTopComponent.forwardButton.text=
CreateTagDialog.cancelButton.text=Cancel
CreateTagDialog.okButton.text=OK
CreateTagDialog.tagNameField.text=
CreateTagDialog.tagNameLabel.text=Tag Name:
CreateTagDialog.preexistingLabel.text=Pre-existing Tags:
CreateTagDialog.newTagPanel.border.title=New Tag
TagAndCommentDialog.tagLabel.text=Tag:
TagAndCommentDialog.tagCombo.toolTipText=Select tag to use
TagAndCommentDialog.cancelButton.text=Cancel
TagAndCommentDialog.okButton.text=OK
TagAndCommentDialog.commentText.toolTipText=Enter an optional tag comment or leave blank
TagAndCommentDialog.commentText.text=
TagAndCommentDialog.commentLabel.text=Comment:
TagAndCommentDialog.newTagButton.text=New Tag

View File

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

View File

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

View File

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

View File

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

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
KnownStatusSearchPanel.knownCheckBox.text=Known Status:
KnownStatusSearchPanel.knownBadOptionCheckBox.text=Known bad
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL)
KnownStatusSearchPanel.knownOptionCheckBox.text=Known (NSRL or other)
KnownStatusSearchPanel.unknownOptionCheckBox.text=Unknown
DateSearchPanel.dateCheckBox.text=Date:
DateSearchPanel.jLabel4.text=Timezone:

View File

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

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">
<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;)"/>
</Property>
</Properties>
<Events>
<EventHandler event="actionPerformed" listener="java.awt.event.ActionListener" parameters="java.awt.event.ActionEvent" handler="knownOptionCheckBoxActionPerformed"/>
</Events>
</Component>
<Component class="javax.swing.JCheckBox" name="knownBadOptionCheckBox">
<Properties>

View File

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

View File

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

View File

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

View File

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

View File

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

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
*/
public void fireModuleDataEvent(ModuleDataEvent moduleDataEvent) {
@ -120,6 +121,7 @@ public class IngestServices {
/**
* Fire module content event to notify registered module content event listeners
* that there is new content (from ZIP file contents, carving, etc.)
* @param moduleContentEvent module content event, encapsulating content changed
*/
public void fireModuleContentEvent(ModuleContentEvent moduleContentEvent) {

View File

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

View File

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

View File

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

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
public String getName() {
String name = "Body File";
String name = "TSK Body File";
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.
* Note: This method is a temporary workaround to avoid modifying the TableReportModule interface.
@ -162,7 +128,8 @@ public class ReportExcel implements TableReportModule {
* @param name Name of the data type
* @param comment Comment on the data type, may be the empty string
*/
public void startDataType(String name, String comment) {
@Override
public void startDataType(String name, String description) {
// Create a worksheet for the data type (assumed to be an artifact type).
name = escapeForExcel(name);
sheet = wb.createSheet(name);
@ -183,10 +150,10 @@ public class ReportExcel implements TableReportModule {
++rowIndex;
// Add a comment row, if a comment was supplied.
if (!comment.isEmpty()) {
if (!description.isEmpty()) {
row = sheet.createRow(rowIndex);
row.setRowStyle(setStyle);
row.createCell(0).setCellValue(comment);
row.createCell(0).setCellValue(description);
++rowIndex;
}
@ -310,7 +277,7 @@ public class ReportExcel implements TableReportModule {
@Override
public String getName() {
return "Excel";
return "Results - Excel";
}
@Override

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

@ -48,56 +48,61 @@ public class ReportProgressPanel extends javax.swing.JPanel {
}
private void customInit(String reportName, String reportPath) {
reportLabel.setText(reportName);
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
pathLabel.setToolTipText(reportPath);
reportProgressBar.setIndeterminate(true);
reportProgressBar.setMaximum(100);
reportLabel.setText(reportName);
processingLabel.setText("Queuing...");
STATUS = ReportStatus.QUEUING;
if (reportPath != null) {
pathLabel.setText("<html><u>" + shortenPath(reportPath) + "</u></html>");
pathLabel.setToolTipText(reportPath);
// Add the "link" effect to the pathLabel
final String linkPath = reportPath;
pathLabel.addMouseListener(new MouseListener() {
final String linkPath = reportPath;
pathLabel.addMouseListener(new MouseListener() {
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mouseClicked(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mousePressed(MouseEvent e) {
}
@Override
public void mouseReleased(MouseEvent e) {
File file = new File(linkPath);
try {
Desktop.getDesktop().open(file);
} catch (IOException ex) {
} catch (IllegalArgumentException ex) {
@Override
public void mouseReleased(MouseEvent e) {
File file = new File(linkPath);
try {
// try to open the parent path if the file doens't exist
Desktop.getDesktop().open(file.getParentFile());
} catch (IOException ex1) {
Desktop.getDesktop().open(file);
} catch (IOException ex) {
} catch (IllegalArgumentException ex) {
try {
// try to open the parent path if the file doens't exist
Desktop.getDesktop().open(file.getParentFile());
} catch (IOException ex1) {
}
}
}
}
@Override
public void mouseEntered(MouseEvent e) {
pathLabel.setForeground(Color.DARK_GRAY);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
public void mouseEntered(MouseEvent e) {
pathLabel.setForeground(Color.DARK_GRAY);
setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
pathLabel.setForeground(Color.BLACK);
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
@Override
public void mouseExited(MouseEvent e) {
pathLabel.setForeground(Color.BLACK);
setCursor(Cursor.getPredefinedCursor(Cursor.DEFAULT_CURSOR));
}
});
});
}
else {
pathLabel.setText("<html><u>No report file</u></html>");
}
}
/**

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