Merge pull request #7247 from rcordovano/7977-fix-analysis-result-tagging

7977 fix analysis result tagging
This commit is contained in:
Richard Cordovano 2021-09-09 10:23:41 -04:00 committed by GitHub
commit fadf8abf3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 153 additions and 43 deletions

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2019 Basis Technology Corp. * Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -29,6 +29,7 @@ import org.openide.windows.WindowManager;
import org.sleuthkit.autopsy.casemodule.Case; import org.sleuthkit.autopsy.casemodule.Case;
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException; import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactItem;
import org.sleuthkit.datamodel.BlackboardArtifact; import org.sleuthkit.datamodel.BlackboardArtifact;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.TagName; import org.sleuthkit.datamodel.TagName;
@ -46,6 +47,8 @@ import org.sleuthkit.datamodel.TskCoreException;
}) })
public class AddBlackboardArtifactTagAction extends AddTagAction { public class AddBlackboardArtifactTagAction extends AddTagAction {
private static final long serialVersionUID = 1L;
// This class is a singleton to support multi-selection of nodes, since // 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 // 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). // node in the array returns a reference to the same action object from Node.getActions(boolean).
@ -82,8 +85,14 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
* invocation of addTag(), we don't want to tag the same * invocation of addTag(), we don't want to tag the same
* BlackboardArtifact more than once, so we dedupe the * BlackboardArtifact more than once, so we dedupe the
* BlackboardArtifacts by stuffing them into a HashSet. * BlackboardArtifacts by stuffing them into a HashSet.
*
* RC (9/8/21): The documentation does NOT say that lookupAll() can
* return duplicates. That would be very broken. What motivated this
* "de-duping" ?
*/ */
selectedArtifacts.addAll(Utilities.actionsGlobalContext().lookupAll(BlackboardArtifact.class)); for (BlackboardArtifactItem<?> item : Utilities.actionsGlobalContext().lookupAll(BlackboardArtifactItem.class)) {
selectedArtifacts.add(item.getTskContent());
}
} else { } else {
for (Content content : getContentToTag()) { for (Content content : getContentToTag()) {
if (content instanceof BlackboardArtifact) { if (content instanceof BlackboardArtifact) {
@ -111,4 +120,10 @@ public class AddBlackboardArtifactTagAction extends AddTagAction {
} }
}).start(); }).start();
} }
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2013-2020 Basis Technology Corp. * Copyright 2013-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -44,22 +44,29 @@ import org.sleuthkit.datamodel.TskCoreException;
import org.sleuthkit.datamodel.TskData; import org.sleuthkit.datamodel.TskData;
/** /**
* An abstract base class for Actions that allow users to tag SleuthKit data * An abstract super class for Actions that allow users to tag Sleuth Kit data
* model objects. * model objects.
*/ */
abstract class AddTagAction extends AbstractAction implements Presenter.Popup { abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
private static final long serialVersionUID = 1L; private static final long serialVersionUID = 1L;
private static final String NO_COMMENT = ""; private static final String NO_COMMENT = "";
private final Collection<Content> content = new HashSet<>(); private final Collection<Content> contentObjsToTag;
/**
* Constructs an instance of an abstract super class for Actions that allow
* users to tag Sleuth Kit data model objects.
*
* @param menuText The menu item text.
*/
AddTagAction(String menuText) { AddTagAction(String menuText) {
super(menuText); super(menuText);
contentObjsToTag = new HashSet<>();
} }
@Override @Override
public JMenuItem getPopupPresenter() { public JMenuItem getPopupPresenter() {
content.clear(); contentObjsToTag.clear();
return new TagMenu(); return new TagMenu();
} }
@ -70,7 +77,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
* @return The specified content for this action. * @return The specified content for this action.
*/ */
Collection<Content> getContentToTag() { Collection<Content> getContentToTag() {
return Collections.unmodifiableCollection(content); return Collections.unmodifiableCollection(contentObjsToTag);
} }
/** /**
@ -83,8 +90,8 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
* apply to the Content specified. * apply to the Content specified.
*/ */
public JMenuItem getMenuForContent(Collection<? extends Content> contentToTag) { public JMenuItem getMenuForContent(Collection<? extends Content> contentToTag) {
content.clear(); contentObjsToTag.clear();
content.addAll(contentToTag); contentObjsToTag.addAll(contentToTag);
return new TagMenu(); return new TagMenu();
} }
@ -111,6 +118,11 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
*/ */
abstract protected void addTag(TagName tagName, String comment); abstract protected void addTag(TagName tagName, String comment);
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
/** /**
* Instances of this class implement a context menu user interface for * 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 * creating or selecting a tag name for a tag and specifying an optional tag
@ -126,7 +138,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
super(getActionDisplayName()); super(getActionDisplayName());
// Get the current set of tag names. // Get the current set of tag names.
Map<String, TagName> tagNamesMap = null; Map<String, TagName> tagNamesMap;
List<String> standardTagNames = TagsManager.getStandardTagNames(); List<String> standardTagNames = TagsManager.getStandardTagNames();
Map<String, JMenu> tagSetMenuMap = new HashMap<>(); Map<String, JMenu> tagSetMenuMap = new HashMap<>();
List<JMenuItem> standardTagMenuitems = new ArrayList<>(); List<JMenuItem> standardTagMenuitems = new ArrayList<>();
@ -240,5 +252,7 @@ abstract class AddTagAction extends AbstractAction implements Presenter.Popup {
return tagNameItem; return tagNameItem;
} }
} }
} }

View File

@ -132,7 +132,7 @@ public class AnalysisResultsContentViewer implements DataContentViewer {
return true; return true;
} }
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); TskContentItem<?> contentItem = node.getLookup().lookup(TskContentItem.class);
if (!Objects.isNull(contentItem)) { if (!Objects.isNull(contentItem)) {
Content content = contentItem.getTskContent(); Content content = contentItem.getTskContent();
try { try {

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2021 Basis Technology Corp. * Copyright 2021-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -251,7 +251,7 @@ public class AnalysisResultsViewModel {
* selected in the content viewer and get the analyzed content * selected in the content viewer and get the analyzed content
* as the source of the analysis results to display. * as the source of the analysis results to display.
*/ */
selectedAnalysisResult = analysisResultItem.getAnalysisResult(); selectedAnalysisResult = analysisResultItem.getTskContent();
selectedObjectId = selectedAnalysisResult.getId(); selectedObjectId = selectedAnalysisResult.getId();
analyzedContent = selectedAnalysisResult.getParent(); analyzedContent = selectedAnalysisResult.getParent();
} else { } else {
@ -260,7 +260,7 @@ public class AnalysisResultsViewModel {
* an analysis result. Use it as the source of the analysis * an analysis result. Use it as the source of the analysis
* results to display. * results to display.
*/ */
TskContentItem contentItem = node.getLookup().lookup(TskContentItem.class); TskContentItem<?> contentItem = node.getLookup().lookup(TskContentItem.class);
analyzedContent = contentItem.getTskContent(); analyzedContent = contentItem.getTskContent();
selectedObjectId = analyzedContent.getId(); selectedObjectId = analyzedContent.getId();
} }

View File

@ -1,7 +1,7 @@
/* /*
* Autopsy Forensic Browser * Autopsy Forensic Browser
* *
* Copyright 2011-2019 Basis Technology Corp. * Copyright 2012-2021 Basis Technology Corp.
* Contact: carrier <at> sleuthkit <dot> org * Contact: carrier <at> sleuthkit <dot> org
* *
* Licensed under the Apache License, Version 2.0 (the "License"); * Licensed under the Apache License, Version 2.0 (the "License");
@ -39,7 +39,6 @@ import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeIns
import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type; import org.sleuthkit.autopsy.centralrepository.datamodel.CorrelationAttributeInstance.Type;
import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable; import org.sleuthkit.autopsy.corecomponents.DataResultViewerTable;
import org.sleuthkit.autopsy.coreutils.Logger; import org.sleuthkit.autopsy.coreutils.Logger;
import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE; import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
import org.sleuthkit.datamodel.Content; import org.sleuthkit.datamodel.Content;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
@ -102,7 +101,7 @@ public abstract class AbstractContentNode<T extends Content> extends ContentNode
* @param content Underlying Content instances * @param content Underlying Content instances
*/ */
AbstractContentNode(T content) { AbstractContentNode(T content) {
this(content, Lookups.fixed(content, new TskContentItem(content))); this(content, Lookups.fixed(content, new TskContentItem<>(content)));
} }
/** /**

View File

@ -22,30 +22,20 @@ import com.google.common.annotations.Beta;
import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.AnalysisResult;
/** /**
* An Autopsy Data Model item with an underlying analysis result Sleuth Kit Data * An Autopsy Data Model item with an underlying AnalysisResult Sleuth Kit Data
* Model object. * Model object.
*/ */
public class AnalysisResultItem extends TskContentItem { public class AnalysisResultItem extends BlackboardArtifactItem<AnalysisResult> {
/** /**
* Constructs an Autopsy Data Model item with an underlying AnalysisResult * Constructs an Autopsy Data Model item with an underlying AnalysisResult
* Sleuth Kit Data Model object. * Sleuth Kit Data Model object.
* *
* @param analysisResult The analysis result. * @param analysisResult The AnalysisResult object.
*/ */
@Beta @Beta
AnalysisResultItem(AnalysisResult analysisResult) { AnalysisResultItem(AnalysisResult analysisResult) {
super(analysisResult); super(analysisResult);
} }
/**
* Gets the underlying analysis result.
*
* @return The analysis result.
*/
@Beta
public AnalysisResult getAnalysisResult() {
return (AnalysisResult) (getTskContent());
}
} }

View File

@ -0,0 +1,44 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021-2021 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 com.google.common.annotations.Beta;
import org.sleuthkit.datamodel.BlackboardArtifact;
/**
* An abstract super class for an Autopsy Data Model item class with an
* underlying BlackboardArtifact Sleuth Kit Data Model object, i.e., a
* DataArtifact or an AnalysisResult.
*
* @param <T> The concrete BlackboardArtifact sub class type.
*/
public abstract class BlackboardArtifactItem<T extends BlackboardArtifact> extends TskContentItem<T> {
/**
* Constructs an Autopsy Data Model item with an underlying
* BlackboardArtifact Sleuth Kit Data Model object.
*
* @param blackboardArtifact The BlackboardArtifact object.
*/
@Beta
BlackboardArtifactItem(T blackboardArtifact) {
super(blackboardArtifact);
}
}

View File

@ -81,6 +81,7 @@ import org.sleuthkit.autopsy.texttranslation.TextTranslationService;
import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask; import org.sleuthkit.autopsy.datamodel.utils.FileNameTransTask;
import org.sleuthkit.datamodel.AnalysisResult; import org.sleuthkit.datamodel.AnalysisResult;
import org.sleuthkit.datamodel.BlackboardArtifact.Category; import org.sleuthkit.datamodel.BlackboardArtifact.Category;
import org.sleuthkit.datamodel.DataArtifact;
import org.sleuthkit.datamodel.Score; import org.sleuthkit.datamodel.Score;
/** /**
@ -366,18 +367,22 @@ public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifa
* *
* NOTE: The creation of an Autopsy Data Model independent of the * NOTE: The creation of an Autopsy Data Model independent of the
* NetBeans nodes is a work in progress. At the time this comment is * NetBeans nodes is a work in progress. At the time this comment is
* being written, this object is only used by the analysis content * being written, this object is only being used to indicate the item
* viewer. * represented by this BlackboardArtifactNode.
*/ */
TskContentItem artifactItem; BlackboardArtifactItem<?> artifactItem;
if (artifact instanceof AnalysisResult) { if (artifact instanceof AnalysisResult) {
artifactItem = new AnalysisResultItem((AnalysisResult) artifact); artifactItem = new AnalysisResultItem((AnalysisResult) artifact);
} else { } else {
artifactItem = new TskContentItem(artifact); artifactItem = new DataArtifactItem((DataArtifact) artifact);
} }
/* /*
* Create the Lookup. * Create the Lookup.
*
* NOTE: For now, we are putting both the Autopsy Data Model item and
* the Sleuth Kit Data Model item in the Lookup so that code that is not
* aware of the new Autopsy Data Model will still function.
*/ */
if (content == null) { if (content == null) {
return Lookups.fixed(artifact, artifactItem); return Lookups.fixed(artifact, artifactItem);

View File

@ -0,0 +1,41 @@
/*
* Autopsy Forensic Browser
*
* Copyright 2021-2021 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 com.google.common.annotations.Beta;
import org.sleuthkit.datamodel.DataArtifact;
/**
* An Autopsy Data Model item with an underlying DataArtifact Sleuth Kit Data
* Model object.
*/
public class DataArtifactItem extends BlackboardArtifactItem<DataArtifact> {
/**
* Constructs an Autopsy Data Model item with an underlying DataArtifact
* Sleuth Kit Data Model object.
*
* @param dataArtifact The DataArtifact object.
*/
@Beta
DataArtifactItem(DataArtifact dataArtifact) {
super(dataArtifact);
}
}

View File

@ -24,23 +24,25 @@ import org.sleuthkit.datamodel.Content;
/** /**
* An Autopsy Data Model item with an underlying Sleuth Kit Data Model object * An Autopsy Data Model item with an underlying Sleuth Kit Data Model object
* that implements the Sleuth Kit Data Model's Content interface. * that implements the Sleuth Kit Data Model's Content interface.
*
* @param <T> The type of the underlying Sleuth Kit Data Model object.
*/ */
@Beta @Beta
public class TskContentItem { public class TskContentItem<T extends Content> {
private final Content tskContent; private final T content;
/** /**
* Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data * Constructs an Autopsy Data Model item with an underlying Sleuth Kit Data
* Model object that implements the Sleuth Kit Data Model's Content * Model object that implements the Sleuth Kit Data Model's Content
* interface. * interface.
* *
* @param content The underlying Sleuth Kit Data Model object. * @param content The Sleuth Kit Data Model object.
* *
*/ */
@Beta @Beta
TskContentItem(Content sleuthKitContent) { TskContentItem(T content) {
this.tskContent = sleuthKitContent; this.content = content;
} }
/** /**
@ -49,8 +51,8 @@ public class TskContentItem {
* @return The Sleuth Kit Data Model object. * @return The Sleuth Kit Data Model object.
*/ */
@Beta @Beta
public Content getTskContent() { public T getTskContent() {
return tskContent; return content;
} }
} }