mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-15 09:17:42 +00:00
Added delete tag capability to new tags api
This commit is contained in:
parent
d74fa2e894
commit
b65a9e6d5a
@ -46,6 +46,7 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
}
|
||||
|
||||
private AddBlackboardArtifactTagAction() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -57,7 +58,6 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
|
||||
protected void addTag(TagName tagName, String comment) {
|
||||
Collection<? extends BlackboardArtifact> selectedArtifacts = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class);
|
||||
for (BlackboardArtifact artifact : selectedArtifacts) {
|
||||
Tags.createTag(artifact, tagName.getDisplayName(), comment); //RJCTODO: Jettision this
|
||||
try {
|
||||
Case.getCurrentCase().getServices().getTagsManager().addBlackboardArtifactTag(artifact, tagName, comment);
|
||||
}
|
||||
|
@ -46,6 +46,7 @@ public class AddContentTagAction extends AddTagAction {
|
||||
}
|
||||
|
||||
private AddContentTagAction() {
|
||||
super("");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -57,7 +58,6 @@ public class AddContentTagAction extends AddTagAction {
|
||||
protected void addTag(TagName tagName, String comment) {
|
||||
Collection<? extends AbstractFile> selectedFiles = Utilities.actionsGlobalContext().lookupAll(AbstractFile.class);
|
||||
for (AbstractFile file : selectedFiles) {
|
||||
Tags.createTag(file, tagName.getDisplayName(), comment); //RJCTODO: Jettision this
|
||||
try {
|
||||
Case.getCurrentCase().getServices().getTagsManager().addContentTag(file, tagName, comment);
|
||||
}
|
||||
|
@ -35,16 +35,20 @@ import org.sleuthkit.datamodel.TagName;
|
||||
* An abstract base class for Actions that allow users to tag SleuthKit data
|
||||
* model objects.
|
||||
*/
|
||||
abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
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
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
protected void doAction(ActionEvent event) {
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,14 +63,6 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
*/
|
||||
abstract protected void addTag(TagName tagName, String comment);
|
||||
|
||||
private void refreshDirectoryTree() {
|
||||
//TODO instead should send event to node children, which will call its refresh() / refreshKeys()
|
||||
// RJCTODO: Explain what is going on here and pare to one refreshTree() call.
|
||||
DirectoryTreeTopComponent viewer = DirectoryTreeTopComponent.findInstance();
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
viewer.refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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
|
||||
@ -90,7 +86,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
// 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 (tagNames.isEmpty()) {
|
||||
if (!tagNames.isEmpty()) {
|
||||
for (final TagName tagName : tagNames) {
|
||||
JMenuItem tagNameItem = new JMenuItem(tagName.getDisplayName());
|
||||
tagNameItem.addActionListener(new ActionListener() {
|
||||
@ -114,7 +110,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
// 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("Choose Tag...");
|
||||
JMenuItem newTagMenuItem = new JMenuItem("New Tag...");
|
||||
newTagMenuItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
@ -127,10 +123,10 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
|
||||
});
|
||||
quickTagMenu.add(newTagMenuItem);
|
||||
|
||||
// Create a "Choose Tag and Comment..." menu item. Selecting this itme initiates
|
||||
// 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("Choose Tag and Comment...");
|
||||
JMenuItem tagAndCommentItem = new JMenuItem("Tag and Comment...");
|
||||
tagAndCommentItem.addActionListener(new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
|
@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifactTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to blackboard artifacts.
|
||||
*/
|
||||
public class DeleteBlackboardArtifactTagAction extends TagAction {
|
||||
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||
|
||||
// This class is a singleton to support multi-selection of nodes, since
|
||||
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||
private static DeleteBlackboardArtifactTagAction instance;
|
||||
|
||||
public static synchronized DeleteBlackboardArtifactTagAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new DeleteBlackboardArtifactTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DeleteBlackboardArtifactTagAction() {
|
||||
super(MENU_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(ActionEvent event) {
|
||||
Collection<? extends BlackboardArtifactTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactTag.class);
|
||||
for (BlackboardArtifactTag tag : selectedTags) {
|
||||
try {
|
||||
Case.getCurrentCase().getServices().getTagsManager().deleteBlackboardArtifactTag(tag);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
|
||||
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
66
Core/src/org/sleuthkit/autopsy/actions/DeleteContentTagAction.java
Executable file
@ -0,0 +1,66 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import java.util.Collection;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import javax.swing.JOptionPane;
|
||||
import org.openide.util.Utilities;
|
||||
import org.sleuthkit.autopsy.casemodule.Case;
|
||||
import org.sleuthkit.datamodel.ContentTag;
|
||||
import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* Instances of this Action allow users to delete tags applied to content.
|
||||
*/
|
||||
public class DeleteContentTagAction extends TagAction {
|
||||
private static final String MENU_TEXT = "Delete Tag(s)";
|
||||
|
||||
// This class is a singleton to support multi-selection of nodes, since
|
||||
// org.openide.nodes.NodeOp.findActions(Node[] nodes) will only pick up an Action if every
|
||||
// node in the array returns a reference to the same action object from Node.getActions(boolean).
|
||||
private static DeleteContentTagAction instance;
|
||||
|
||||
public static synchronized DeleteContentTagAction getInstance() {
|
||||
if (null == instance) {
|
||||
instance = new DeleteContentTagAction();
|
||||
}
|
||||
return instance;
|
||||
}
|
||||
|
||||
private DeleteContentTagAction() {
|
||||
super(MENU_TEXT);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doAction(ActionEvent e) {
|
||||
Collection<? extends ContentTag> selectedTags = Utilities.actionsGlobalContext().lookupAll(ContentTag.class);
|
||||
for (ContentTag tag : selectedTags) {
|
||||
try {
|
||||
Case.getCurrentCase().getServices().getTagsManager().deleteContentTag(tag);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(AddContentTagAction.class.getName()).log(Level.SEVERE, "Error deleting tag", ex);
|
||||
JOptionPane.showMessageDialog(null, "Unable to delete tag " + tag.getName() + ".", "Tag Deletion Error", JOptionPane.ERROR_MESSAGE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
62
Core/src/org/sleuthkit/autopsy/actions/TagAction.java
Executable file
@ -0,0 +1,62 @@
|
||||
/*
|
||||
* Autopsy Forensic Browser
|
||||
*
|
||||
* Copyright 2013 Basis Technology Corp.
|
||||
* Contact: carrier <at> sleuthkit <dot> org
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package org.sleuthkit.autopsy.actions;
|
||||
|
||||
import java.awt.event.ActionEvent;
|
||||
import javax.swing.AbstractAction;
|
||||
import org.sleuthkit.autopsy.directorytree.DirectoryTreeTopComponent;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
|
||||
/**
|
||||
* Abstract base class for Actions involving tags.
|
||||
*/
|
||||
public abstract class TagAction extends AbstractAction {
|
||||
public TagAction(String menuText) {
|
||||
super(menuText);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent event) {
|
||||
doAction(event);
|
||||
refreshDirectoryTree();
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived classes must implement this Template Method for actionPerformed().
|
||||
* @param event ActionEvent object passed to actionPerformed()
|
||||
*/
|
||||
abstract protected void doAction(ActionEvent event);
|
||||
|
||||
/**
|
||||
* Derived classes should call this method any time a tag is created, updated
|
||||
* or deleted outside of an actionPerformed() call.
|
||||
*/
|
||||
protected void refreshDirectoryTree() {
|
||||
// The way the "directory tree" currently works, a new tags sub-tree
|
||||
// needs to be made to reflect the results of invoking tag Actions. The
|
||||
// way to do this is to call DirectoryTreeTopComponent.refreshTree(),
|
||||
// which calls RootContentChildren.refreshKeys(BlackboardArtifact.ARTIFACT_TYPE... types)
|
||||
// for the RootContentChildren object that is the child factory for the
|
||||
// ResultsNode that is the root of the tags sub-tree. There is a switch
|
||||
// statement in RootContentChildren.refreshKeys() that maps both
|
||||
// BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE and BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_ARTIFACT
|
||||
// to making a call to refreshKey(TagsNodeKey).
|
||||
DirectoryTreeTopComponent.findInstance().refreshTree(BlackboardArtifact.ARTIFACT_TYPE.TSK_TAG_FILE);
|
||||
}
|
||||
}
|
@ -37,20 +37,105 @@ import org.sleuthkit.datamodel.TskCoreException;
|
||||
|
||||
/**
|
||||
* A singleton instance of this class functions as an Autopsy service that
|
||||
* manages the creation, updating, and deletion of tags applied to Content and
|
||||
* BlackboardArtifacts objects by users.
|
||||
* 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_FILE_NAME = "tags";
|
||||
private static final String TAG_NAMES_SETTING_KEY = "tagNames";
|
||||
private static final String TAGS_SETTINGS_NAME = "Tags";
|
||||
private static final String TAG_NAMES_SETTING_KEY = "TagNames";
|
||||
private static final TagName[] predefinedTagNames = new TagName[]{new TagName("Bookmark", "", TagName.HTML_COLOR.NONE)};
|
||||
private final SleuthkitCase tskCase;
|
||||
private final HashMap<String, TagName> tagNames = new HashMap<>();
|
||||
private final Object lock = new Object();
|
||||
|
||||
// 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 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;
|
||||
loadTagNamesFromTagSettings();
|
||||
getExistingTagNames();
|
||||
saveTagNamesToTagsSettings();
|
||||
}
|
||||
|
||||
|
||||
private void getExistingTagNames() {
|
||||
getTagNamesFromCurrentCase();
|
||||
getTagNamesFromTagsSettings();
|
||||
getPredefinedTagNames();
|
||||
}
|
||||
|
||||
private void getTagNamesFromCurrentCase() {
|
||||
try {
|
||||
ArrayList<TagName> currentTagNames = new ArrayList<>();
|
||||
tskCase.getAllTagNames(currentTagNames);
|
||||
for (TagName tagName : currentTagNames) {
|
||||
tagNames.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 (!tagNames.containsKey(tagNameAttributes[0])) {
|
||||
TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
|
||||
addTagName(tagName, "Failed to add " + tagName.getDisplayName() + " tag name from tag settings to the current case");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void getPredefinedTagNames() {
|
||||
for (TagName tagName : predefinedTagNames) {
|
||||
if (!tagNames.containsKey(tagName.getDisplayName())) {
|
||||
addTagName(tagName, "Failed to add predefined " + tagName.getDisplayName() + " tag name to the current case");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void addTagName(TagName tagName, String errorMessage) {
|
||||
try {
|
||||
tskCase.addTagName(tagName);
|
||||
tagNames.put(tagName.getDisplayName(), tagName);
|
||||
}
|
||||
catch(TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, errorMessage, ex);
|
||||
}
|
||||
}
|
||||
|
||||
private void saveTagNamesToTagsSettings() {
|
||||
if (!tagNames.isEmpty()) {
|
||||
StringBuilder setting = new StringBuilder();
|
||||
for (TagName tagName : tagNames.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());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a list of all tag names currently available for tagging content or
|
||||
* blackboard artifacts.
|
||||
@ -67,27 +152,35 @@ public class TagsManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* RJCTODO: Discard or properly comment
|
||||
* Gets a list of all tag names currently used for tagging content or
|
||||
* blackboard artifacts.
|
||||
* @return [out] A list, possibly empty, of TagName data transfer objects (DTOs).
|
||||
*/
|
||||
public void getTagNamesInUse(List<TagName> tagNames) {
|
||||
try {
|
||||
tagNames.clear();
|
||||
tskCase.getTagNamesInUse(tagNames);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get tag names from the current case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 boolean tagNameExists(String tagDisplayName) {
|
||||
return tagNames.containsKey(tagDisplayName);
|
||||
synchronized(lock) {
|
||||
return tagNames.containsKey(tagDisplayName);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* RJCTODO: Discard or properly comment
|
||||
*/
|
||||
public TagName getTagName(String tagDisplayName) {
|
||||
if (!tagNames.containsKey(tagDisplayName)) {
|
||||
// RJCTODO: Throw exception
|
||||
}
|
||||
|
||||
return tagNames.get(tagDisplayName);
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings file.
|
||||
* @param displayName The display name for the new tag name.
|
||||
* @return A TagName object representing the new tag name on success, null on failure.
|
||||
* @param [in] displayName The display name for the new tag name.
|
||||
* @return A TagName data transfer object (DTO) representing the new tag name.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public TagName addTagName(String displayName) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
@ -96,9 +189,9 @@ public class TagsManager implements Closeable {
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings file.
|
||||
* @param displayName The display name for the new tag name.
|
||||
* @param description The description for the new tag name.
|
||||
* @return A TagName object representing the new tag name on success, null on failure.
|
||||
* @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 TskCoreException
|
||||
*/
|
||||
public TagName addTagName(String displayName, String description) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
@ -107,31 +200,34 @@ public class TagsManager implements Closeable {
|
||||
|
||||
/**
|
||||
* Adds a new tag name to the current case and to the tags settings file.
|
||||
* @param displayName The display name for the new tag name.
|
||||
* @param description The description for the new tag name.
|
||||
* @param color The HTML color to associate with the new tag name.
|
||||
* @return A TagName object representing the new tag name.
|
||||
* @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 TskCoreException
|
||||
*/
|
||||
public synchronized TagName addTagName(String displayName, String description, TagName.HTML_COLOR color) throws TagNameAlreadyExistsException, TskCoreException {
|
||||
if (tagNames.containsKey(displayName)) {
|
||||
throw new TagNameAlreadyExistsException();
|
||||
}
|
||||
synchronized(lock) {
|
||||
if (tagNames.containsKey(displayName)) {
|
||||
throw new TagNameAlreadyExistsException();
|
||||
}
|
||||
|
||||
// Add the tag name to the case.
|
||||
TagName newTagName = new TagName(displayName, description, color);
|
||||
tskCase.addTagName(newTagName);
|
||||
|
||||
// Add the tag name to the tags settings.
|
||||
tagNames.put(newTagName.getDisplayName(), newTagName);
|
||||
saveTagNamesToTagsSettings();
|
||||
|
||||
return newTagName;
|
||||
}
|
||||
}
|
||||
|
||||
TagName newTagName = new TagName(displayName, description, color);
|
||||
tskCase.addTagName(newTagName);
|
||||
tagNames.put(newTagName.getDisplayName(), newTagName);
|
||||
saveTagNamesToTagsSettings();
|
||||
return newTagName;
|
||||
}
|
||||
|
||||
public class TagNameAlreadyExistsException extends Exception {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a Content object.
|
||||
* @param content The Content to tag.
|
||||
* @param tagName The type of tag to add.
|
||||
* Tags a content object.
|
||||
* @param [in] content The content to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addContentTag(Content content, TagName tagName) throws TskCoreException {
|
||||
@ -139,10 +235,10 @@ public class TagsManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a Content object.
|
||||
* @param content The Content to tag.
|
||||
* @param tagName The name to use for the tag.
|
||||
* @param comment A comment to store with the tag.
|
||||
* 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.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addContentTag(Content content, TagName tagName, String comment) throws TskCoreException {
|
||||
@ -150,12 +246,12 @@ public class TagsManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a Content object or a portion of a content object.
|
||||
* @param content The Content to tag.
|
||||
* @param tagName The name to use for the tag.
|
||||
* @param comment A comment to store with the tag.
|
||||
* @param beginByteOffset Designates the beginning of a tagged extent.
|
||||
* @param endByteOffset Designates the end of a tagged extent.
|
||||
* Tags a content object or a portion 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 extent.
|
||||
* @param [in] endByteOffset Designates the end of a tagged extent.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addContentTag(Content content, TagName tagName, String comment, long beginByteOffset, long endByteOffset) throws IllegalArgumentException, TskCoreException {
|
||||
@ -176,7 +272,7 @@ public class TagsManager implements Closeable {
|
||||
|
||||
/**
|
||||
* Deletes a content tag.
|
||||
* @param tag The tag to delete.
|
||||
* @param [in] tag The tag to delete.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void deleteContentTag(ContentTag tag) throws TskCoreException {
|
||||
@ -184,36 +280,11 @@ public class TagsManager implements Closeable {
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a BlackboardArtifact object.
|
||||
* @param artifact The BlackboardArtifact to tag.
|
||||
* @param tagName The name to use for the tag.
|
||||
* @throws TskCoreException
|
||||
* 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.
|
||||
*/
|
||||
public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
|
||||
addBlackboardArtifactTag(artifact, tagName, "");
|
||||
}
|
||||
|
||||
/**
|
||||
* Tags a BlackboardArtifact object.
|
||||
* @param artifact The BlackboardArtifact to tag.
|
||||
* @param tagName The name to use for the tag.
|
||||
* @param comment A comment to store with the tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
|
||||
tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment));
|
||||
}
|
||||
|
||||
void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
|
||||
tskCase.deleteBlackboardArtifactTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* RJCTODO
|
||||
* @param tagName
|
||||
* @return
|
||||
*/
|
||||
public void getContentTags(TagName tagName, List<ContentTag> tags) {
|
||||
public void getContentTagsByTagName(TagName tagName, List<ContentTag> tags) {
|
||||
try {
|
||||
tskCase.getContentTagsByTagName(tagName, tags);
|
||||
}
|
||||
@ -221,13 +292,43 @@ public class TagsManager implements Closeable {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.SEVERE, "Failed to get content tags from the current case", ex);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* RJCTODO
|
||||
* @param tagName
|
||||
* @return
|
||||
* Tags a blackboard artifact object.
|
||||
* @param [in] artifact The blackboard artifact to tag.
|
||||
* @param [in] tagName The name to use for the tag.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void getBlackboardArtifactTags(TagName tagName, List<BlackboardArtifactTag> tags) {
|
||||
public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName) throws TskCoreException {
|
||||
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.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void addBlackboardArtifactTag(BlackboardArtifact artifact, TagName tagName, String comment) throws TskCoreException {
|
||||
tskCase.addBlackboardArtifactTag(new BlackboardArtifactTag(artifact, tskCase.getContentById(artifact.getObjectID()), tagName, comment));
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a blackboard artifact tag.
|
||||
* @param [in] tag The tag to delete.
|
||||
* @throws TskCoreException
|
||||
*/
|
||||
public void deleteBlackboardArtifactTag(BlackboardArtifactTag tag) throws TskCoreException {
|
||||
tskCase.deleteBlackboardArtifactTag(tag);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets blackboard artifact 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.
|
||||
*/
|
||||
public void getBlackboardArtifactTagsByTagName(TagName tagName, List<BlackboardArtifactTag> tags) {
|
||||
try {
|
||||
tskCase.getBlackboardArtifactTagsByTagName(tagName, tags);
|
||||
}
|
||||
@ -239,62 +340,5 @@ public class TagsManager implements Closeable {
|
||||
@Override
|
||||
public void close() throws IOException {
|
||||
saveTagNamesToTagsSettings();
|
||||
}
|
||||
|
||||
private void loadTagNamesFromTagSettings() {
|
||||
// Get any tag names already defined for the current case.
|
||||
try {
|
||||
ArrayList<TagName> currentTagNames = new ArrayList<>();
|
||||
tskCase.getAllTagNames(currentTagNames);
|
||||
for (TagName tagName : currentTagNames) {
|
||||
tagNames.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);
|
||||
}
|
||||
|
||||
// Read the saved tag names, if any, from the tags settings file and
|
||||
// add them to the current case if they haven't already been added, e.g,
|
||||
// when the case was last opened.
|
||||
String setting = ModuleSettings.getConfigSetting(TAGS_SETTINGS_FILE_NAME, TAG_NAMES_SETTING_KEY);
|
||||
if (null != setting && !setting.isEmpty()) {
|
||||
// Read the tag types setting and break in into tag type tuples.
|
||||
List<String> tagNameTuples = Arrays.asList(setting.split(";"));
|
||||
|
||||
// Parse each tuple and add the tag types 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 (!tagNames.containsKey(tagNameAttributes[0])) {
|
||||
TagName tagName = new TagName(tagNameAttributes[0], tagNameAttributes[1], TagName.HTML_COLOR.getColorByName(tagNameAttributes[2]));
|
||||
try {
|
||||
tskCase.addTagName(tagName);
|
||||
tagNames.put(tagName.getDisplayName(),tagName);
|
||||
}
|
||||
catch(TskCoreException ex) {
|
||||
Logger.getLogger(TagsManager.class.getName()).log(Level.WARNING, "Failed to add saved " + tagName.getDisplayName() + " tag name to the current case", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
saveTagNamesToTagsSettings();
|
||||
}
|
||||
}
|
||||
|
||||
private void saveTagNamesToTagsSettings() {
|
||||
if (!tagNames.isEmpty()) {
|
||||
StringBuilder setting = new StringBuilder();
|
||||
for (TagName tagName : tagNames.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_FILE_NAME, TAG_NAMES_SETTING_KEY, setting.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -155,11 +155,6 @@ abstract class AbstractContentChildren<T> extends Keys<T> {
|
||||
return ee.new EmailExtractedRootNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(Tags t) {
|
||||
return t.new TagsRootNode();
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractNode visit(TagsNodeKey tagsNodeKey) {
|
||||
return new TagsNode();
|
||||
|
@ -52,8 +52,6 @@ public interface AutopsyItemVisitor<T> {
|
||||
|
||||
T visit(EmailExtracted ee);
|
||||
|
||||
T visit(Tags t);
|
||||
|
||||
T visit(TagsNodeKey tagsNodeKey);
|
||||
|
||||
T visit(DataSources i);
|
||||
@ -136,11 +134,6 @@ public interface AutopsyItemVisitor<T> {
|
||||
return defaultVisit(ee);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(Tags t) {
|
||||
return defaultVisit(t);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsNodeKey tagsNodeKey) {
|
||||
return defaultVisit(tagsNodeKey);
|
||||
|
@ -18,11 +18,15 @@
|
||||
*/
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
@ -69,6 +73,13 @@ public class BlackboardArtifactTagNode extends DisplayableItemNode {
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(DeleteBlackboardArtifactTagAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
@ -19,11 +19,15 @@
|
||||
|
||||
package org.sleuthkit.autopsy.datamodel;
|
||||
|
||||
import java.util.ArrayList;
|
||||
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;
|
||||
|
||||
@ -68,6 +72,13 @@ public class ContentTagNode extends DisplayableItemNode {
|
||||
return propertySheet;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action[] getActions(boolean context) {
|
||||
List<Action> actions = new ArrayList<>();
|
||||
actions.add(DeleteContentTagAction.getInstance());
|
||||
return actions.toArray(new Action[0]);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T accept(DisplayableItemNodeVisitor<T> v) {
|
||||
return v.visit(this);
|
||||
|
@ -77,7 +77,7 @@ public class ContentTagTypeNode extends DisplayableItemNode {
|
||||
@Override
|
||||
protected boolean createKeys(List<ContentTag> keys) {
|
||||
// Use the content tags bearing the specified tag name as the keys.
|
||||
Case.getCurrentCase().getServices().getTagsManager().getContentTags(tagName, keys);
|
||||
Case.getCurrentCase().getServices().getTagsManager().getContentTagsByTagName(tagName, keys);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -30,9 +30,6 @@ 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;
|
||||
|
||||
/**
|
||||
@ -86,12 +83,6 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
|
||||
T visit(EmailExtractedFolderNode eefn);
|
||||
|
||||
T visit(TagsRootNode bksrn);
|
||||
|
||||
T visit(TagsNodeRoot bksrn);
|
||||
|
||||
T visit(TagNodeRoot tnr);
|
||||
|
||||
T visit(TagsNode node);
|
||||
|
||||
T visit(TagNameNode node);
|
||||
@ -277,21 +268,6 @@ public interface DisplayableItemNodeVisitor<T> {
|
||||
return defaultVisit(ldn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsRootNode bksrn) {
|
||||
return defaultVisit(bksrn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsNodeRoot bksnr) {
|
||||
return defaultVisit(bksnr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagNodeRoot tnr) {
|
||||
return defaultVisit(tnr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public T visit(TagsNode node) {
|
||||
return defaultVisit(node);
|
||||
|
@ -35,7 +35,6 @@ 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);
|
||||
|
@ -79,23 +79,12 @@ public class RootContentChildren extends AbstractContentChildren<Object> {
|
||||
case TSK_EMAIL_MSG:
|
||||
if (o instanceof EmailExtracted)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
break;
|
||||
case TSK_TAG_FILE:
|
||||
if (o instanceof Tags)
|
||||
this.refreshKey(o);
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
|
||||
//TODO check
|
||||
case TSK_TAG_ARTIFACT:
|
||||
if (o instanceof Tags)
|
||||
this.refreshKey(o);
|
||||
if (o instanceof TagsNodeKey)
|
||||
this.refreshKey(o);
|
||||
break;
|
||||
break;
|
||||
default:
|
||||
if (o instanceof ExtractedContent)
|
||||
this.refreshKey(o);
|
||||
|
@ -18,30 +18,15 @@
|
||||
*/
|
||||
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;
|
||||
@ -50,382 +35,12 @@ 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 {
|
||||
public class Tags {
|
||||
|
||||
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 boolean isLeafTypeNode() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 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 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.
|
||||
*
|
||||
@ -448,9 +63,7 @@ public class Tags implements AutopsyVisitableItem {
|
||||
"", comment);
|
||||
attrs.add(attr2);
|
||||
}
|
||||
bookArt.addAttributes(attrs);
|
||||
|
||||
updateTagNamesAppSetting(tagName);
|
||||
bookArt.addAttributes(attrs);
|
||||
}
|
||||
catch (TskCoreException ex) {
|
||||
logger.log(Level.SEVERE, "Failed to create tag for " + file.getName(), ex);
|
||||
@ -488,30 +101,13 @@ public class Tags implements AutopsyVisitableItem {
|
||||
attrs.add(attr1);
|
||||
|
||||
attrs.add(attr3);
|
||||
bookArt.addAttributes(attrs);
|
||||
|
||||
updateTagNamesAppSetting(tagName);
|
||||
bookArt.addAttributes(attrs);
|
||||
}
|
||||
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.
|
||||
*
|
||||
@ -557,7 +153,6 @@ public class Tags implements AutopsyVisitableItem {
|
||||
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);
|
||||
|
@ -43,6 +43,10 @@ public class TagsNode extends DisplayableItemNode {
|
||||
this.setIconBaseWithExtension(ICON_PATH);
|
||||
}
|
||||
|
||||
public static String getNodeName() {
|
||||
return DISPLAY_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLeafTypeNode() {
|
||||
return false;
|
||||
@ -70,7 +74,7 @@ public class TagsNode extends DisplayableItemNode {
|
||||
private static class TagNameNodeFactory extends ChildFactory<TagName> {
|
||||
@Override
|
||||
protected boolean createKeys(List<TagName> keys) {
|
||||
Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys); // RJCTODO: Change this call to filtered call
|
||||
Case.getCurrentCase().getServices().getTagsManager().getAllTagNames(keys);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -81,7 +81,7 @@ public class BlackboardArtifactTagTypeNode extends DisplayableItemNode {
|
||||
@Override
|
||||
protected boolean createKeys(List<BlackboardArtifactTag> keys) {
|
||||
// Use the blackboard artifact tags bearing the specified tag name as the keys.
|
||||
Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTags(tagName, keys);
|
||||
Case.getCurrentCase().getServices().getTagsManager().getBlackboardArtifactTagsByTagName(tagName, keys);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -63,8 +63,6 @@ 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.datamodel.AbstractFile;
|
||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||
@ -405,16 +403,6 @@ public class DataResultFilterNode extends FilterNode {
|
||||
return openChild(atn);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(TagsNodeRoot tnr) {
|
||||
return openChild(tnr);
|
||||
}
|
||||
|
||||
@Override
|
||||
public AbstractAction visit(DirectoryNode dn) {
|
||||
if (dn.getDisplayName().equals(DirectoryNode.DOTDOTDIR)) {
|
||||
|
Loading…
x
Reference in New Issue
Block a user