mirror of
https://github.com/overcuriousity/autopsy-flatpak.git
synced 2025-07-14 17:06:16 +00:00
Merge pull request #5411 from raman-bt/5707-attchmnt-msg-contentviewer
5707, 5708 attchmnt msg contentviewer
This commit is contained in:
commit
f128d54bb8
@ -18,10 +18,13 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.communications.relationships;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.TreeSet;
|
import java.util.TreeSet;
|
||||||
|
import java.util.function.Consumer;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
@ -32,15 +35,18 @@ import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
|||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
import org.sleuthkit.autopsy.datamodel.FileNode;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
import org.sleuthkit.datamodel.BlackboardArtifact;
|
import org.sleuthkit.datamodel.BlackboardArtifact;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
import org.sleuthkit.datamodel.Content;
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Factory for creating thumbnail children nodes.
|
* Factory for creating thumbnail children nodes.
|
||||||
*/
|
*/
|
||||||
final class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
final class AttachmentThumbnailsChildren extends Children.Keys<AbstractFile> {
|
||||||
|
|
||||||
private static final Logger logger = Logger.getLogger(AttachmentsChildren.class.getName());
|
private static final Logger LOGGER = Logger.getLogger(AttachmentThumbnailsChildren.class.getName());
|
||||||
|
|
||||||
private final Set<BlackboardArtifact> artifacts;
|
private final Set<BlackboardArtifact> artifacts;
|
||||||
|
|
||||||
@ -51,17 +57,16 @@ final class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
|||||||
* The thumbnails will be initialls sorted by size, then name so that they
|
* The thumbnails will be initialls sorted by size, then name so that they
|
||||||
* appear sorted by size by default.
|
* appear sorted by size by default.
|
||||||
*/
|
*/
|
||||||
AttachmentsChildren(Set<BlackboardArtifact> artifacts) {
|
AttachmentThumbnailsChildren(Set<BlackboardArtifact> artifacts) {
|
||||||
super(false);
|
super(false);
|
||||||
|
|
||||||
this.artifacts = artifacts;
|
this.artifacts = artifacts;
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node[] createNodes(AbstractFile t) {
|
protected Node[] createNodes(AbstractFile t) {
|
||||||
return new Node[]{new AttachementNode(t)};
|
return new Node[]{new AttachementThumbnailNode(t)};
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@ -77,15 +82,36 @@ final class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
|||||||
return result;
|
return result;
|
||||||
});
|
});
|
||||||
|
|
||||||
artifacts.forEach((bba) -> {
|
artifacts.forEach(new Consumer<BlackboardArtifact>() {
|
||||||
try {
|
@Override
|
||||||
for (Content childContent : bba.getChildren()) {
|
public void accept(BlackboardArtifact bba) {
|
||||||
if (childContent instanceof AbstractFile) {
|
try {
|
||||||
thumbnails.add((AbstractFile) childContent);
|
// Get the attachments from TSK_ATTACHMENTS attribute.
|
||||||
|
BlackboardAttribute attachmentsAttr = bba.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
|
||||||
|
if (attachmentsAttr != null) {
|
||||||
|
|
||||||
|
String jsonVal = attachmentsAttr.getValueString();
|
||||||
|
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
|
||||||
|
|
||||||
|
Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
|
||||||
|
for (FileAttachment fileAttachment : fileAttachments) {
|
||||||
|
long attachedFileObjId = fileAttachment.getObjectId();
|
||||||
|
if (attachedFileObjId >= 0) {
|
||||||
|
AbstractFile attachedFile = bba.getSleuthkitCase().getAbstractFileById(attachedFileObjId);
|
||||||
|
thumbnails.add(attachedFile);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else { // backward compatibility - email message attachments are derived files, children of the message.
|
||||||
|
for (Content childContent : bba.getChildren()) {
|
||||||
|
if (childContent instanceof AbstractFile) {
|
||||||
|
thumbnails.add((AbstractFile) childContent);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
} catch (TskCoreException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Unable to get children from artifact.", ex); //NON-NLS
|
||||||
}
|
}
|
||||||
} catch (TskCoreException ex) {
|
|
||||||
logger.log(Level.WARNING, "Unable to get children from artifact.", ex); //NON-NLS
|
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -95,9 +121,9 @@ final class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
|||||||
/**
|
/**
|
||||||
* A node for representing a thumbnail.
|
* A node for representing a thumbnail.
|
||||||
*/
|
*/
|
||||||
static class AttachementNode extends FileNode {
|
static class AttachementThumbnailNode extends FileNode {
|
||||||
|
|
||||||
AttachementNode(AbstractFile file) {
|
AttachementThumbnailNode(AbstractFile file) {
|
||||||
super(file, false);
|
super(file, false);
|
||||||
}
|
}
|
||||||
|
|
@ -129,7 +129,7 @@ final class MediaViewer extends JPanel implements RelationshipsViewer, ExplorerM
|
|||||||
|
|
||||||
thumbnailViewer.resetComponent();
|
thumbnailViewer.resetComponent();
|
||||||
|
|
||||||
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentsChildren(artifactList)), tableEM), true, this.getClass().getName()));
|
thumbnailViewer.setNode(new TableFilterNode(new DataResultFilterNode(new AbstractNode(new AttachmentThumbnailsChildren(artifactList)), tableEM), true, this.getClass().getName()));
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
|
@ -18,6 +18,7 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.communications.relationships;
|
package org.sleuthkit.autopsy.communications.relationships;
|
||||||
|
|
||||||
|
import com.google.gson.Gson;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import javax.swing.Action;
|
import javax.swing.Action;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
@ -38,6 +39,8 @@ import static org.sleuthkit.autopsy.communications.relationships.RelationshipsNo
|
|||||||
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
import org.sleuthkit.autopsy.datamodel.BlackboardArtifactNode;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG;
|
||||||
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
|
import static org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE.TSK_MESSAGE;
|
||||||
|
import org.sleuthkit.datamodel.BlackboardAttribute;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
|
* Wraps a BlackboardArtifact as an AbstractNode for use in an OutlookView
|
||||||
@ -97,7 +100,7 @@ class MessageNode extends BlackboardArtifactNode {
|
|||||||
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
sheetSet.put(new NodeProperty<>("Subject", Bundle.MessageNode_Node_Property_Subject(), "",
|
||||||
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
getAttributeDisplayString(artifact, TSK_SUBJECT))); //NON-NLS
|
||||||
try {
|
try {
|
||||||
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", artifact.getChildrenCount())); //NON-NLS
|
sheetSet.put(new NodeProperty<>("Attms", Bundle.MessageNode_Node_Property_Attms(), "", getAttachmentsCount())); //NON-NLS
|
||||||
} catch (TskCoreException ex) {
|
} catch (TskCoreException ex) {
|
||||||
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
|
logger.log(Level.WARNING, "Error loading attachment count for " + artifact, ex); //NON-NLS
|
||||||
}
|
}
|
||||||
@ -144,4 +147,21 @@ class MessageNode extends BlackboardArtifactNode {
|
|||||||
public Action getPreferredAction() {
|
public Action getPreferredAction() {
|
||||||
return preferredAction;
|
return preferredAction;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private int getAttachmentsCount() throws TskCoreException {
|
||||||
|
final BlackboardArtifact artifact = getArtifact();
|
||||||
|
int attachmentsCount;
|
||||||
|
|
||||||
|
// Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
|
||||||
|
BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
|
||||||
|
if (attachmentsAttr != null) {
|
||||||
|
String jsonVal = attachmentsAttr.getValueString();
|
||||||
|
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
|
||||||
|
attachmentsCount = msgAttachments.getAttachmentsCount();
|
||||||
|
} else { // legacy attachments may be children of message artifact.
|
||||||
|
attachmentsCount = artifact.getChildrenCount();
|
||||||
|
}
|
||||||
|
|
||||||
|
return attachmentsCount;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -18,15 +18,17 @@
|
|||||||
*/
|
*/
|
||||||
package org.sleuthkit.autopsy.contentviewers;
|
package org.sleuthkit.autopsy.contentviewers;
|
||||||
|
|
||||||
|
import org.sleuthkit.autopsy.datamodel.AttachmentNode;
|
||||||
|
import com.google.gson.Gson;
|
||||||
import java.awt.Color;
|
import java.awt.Color;
|
||||||
import java.awt.Component;
|
import java.awt.Component;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
import java.util.HashSet;
|
import java.util.HashSet;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Optional;
|
import java.util.Optional;
|
||||||
import java.util.Set;
|
import java.util.Set;
|
||||||
import java.util.logging.Level;
|
import java.util.logging.Level;
|
||||||
import java.util.stream.Collectors;
|
|
||||||
import javax.swing.text.JTextComponent;
|
import javax.swing.text.JTextComponent;
|
||||||
import org.apache.commons.lang3.StringUtils;
|
import org.apache.commons.lang3.StringUtils;
|
||||||
import org.jsoup.Jsoup;
|
import org.jsoup.Jsoup;
|
||||||
@ -35,15 +37,12 @@ import org.openide.explorer.ExplorerManager;
|
|||||||
import org.openide.nodes.AbstractNode;
|
import org.openide.nodes.AbstractNode;
|
||||||
import org.openide.nodes.Children;
|
import org.openide.nodes.Children;
|
||||||
import org.openide.nodes.Node;
|
import org.openide.nodes.Node;
|
||||||
import org.openide.nodes.Sheet;
|
|
||||||
import org.openide.util.NbBundle;
|
import org.openide.util.NbBundle;
|
||||||
import org.openide.util.lookup.ServiceProvider;
|
import org.openide.util.lookup.ServiceProvider;
|
||||||
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
import org.sleuthkit.autopsy.corecomponentinterfaces.DataContentViewer;
|
||||||
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
import org.sleuthkit.autopsy.corecomponents.DataResultPanel;
|
||||||
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
import org.sleuthkit.autopsy.corecomponents.TableFilterNode;
|
||||||
import org.sleuthkit.autopsy.coreutils.Logger;
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
import org.sleuthkit.autopsy.datamodel.AbstractAbstractFileNode;
|
|
||||||
import org.sleuthkit.autopsy.datamodel.FileNode;
|
|
||||||
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
import org.sleuthkit.autopsy.directorytree.DataResultFilterNode;
|
||||||
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
import org.sleuthkit.datamodel.AbstractFile;
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
@ -67,7 +66,12 @@ import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHO
|
|||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_PHONE_NUMBER_TO;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_SUBJECT;
|
||||||
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
|
import static org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE.TSK_TEXT;
|
||||||
|
import org.sleuthkit.datamodel.Content;
|
||||||
import org.sleuthkit.datamodel.TskCoreException;
|
import org.sleuthkit.datamodel.TskCoreException;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.MessageAttachments;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.Attachment;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.URLAttachment;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Shows SMS/MMS/EMail messages
|
* Shows SMS/MMS/EMail messages
|
||||||
@ -541,11 +545,34 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void configureAttachments() throws TskCoreException {
|
private void configureAttachments() throws TskCoreException {
|
||||||
//TODO: Replace this with code to get the actual attachements!
|
|
||||||
final Set<AbstractFile> attachments = artifact.getChildren().stream()
|
final Set<Attachment> attachments;
|
||||||
.filter(AbstractFile.class::isInstance)
|
|
||||||
.map(AbstractFile.class::cast)
|
// Attachments are specified in an attribute TSK_ATTACHMENTS as JSON attribute
|
||||||
.collect(Collectors.toSet());
|
BlackboardAttribute attachmentsAttr = artifact.getAttribute(new BlackboardAttribute.Type(BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ATTACHMENTS));
|
||||||
|
if(attachmentsAttr != null) {
|
||||||
|
|
||||||
|
attachments = new HashSet<>();
|
||||||
|
String jsonVal = attachmentsAttr.getValueString();
|
||||||
|
MessageAttachments msgAttachments = new Gson().fromJson(jsonVal, MessageAttachments.class);
|
||||||
|
|
||||||
|
Collection<FileAttachment> fileAttachments = msgAttachments.getFileAttachments();
|
||||||
|
for (FileAttachment fileAttachment: fileAttachments) {
|
||||||
|
attachments.add(fileAttachment);
|
||||||
|
}
|
||||||
|
Collection<URLAttachment> urlAttachments = msgAttachments.getUrlAttachments();
|
||||||
|
for (URLAttachment urlAttachment: urlAttachments) {
|
||||||
|
attachments.add(urlAttachment);
|
||||||
|
}
|
||||||
|
} else { // For backward compatibility - email attachements are derived files and children of the email message artifact
|
||||||
|
attachments = new HashSet<>();
|
||||||
|
for (Content child: artifact.getChildren()) {
|
||||||
|
if (child instanceof AbstractFile) {
|
||||||
|
attachments.add(new FileAttachment((AbstractFile)child));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
final int numberOfAttachments = attachments.size();
|
final int numberOfAttachments = attachments.size();
|
||||||
|
|
||||||
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
msgbodyTabbedPane.setEnabledAt(ATTM_TAB_INDEX, numberOfAttachments > 0);
|
||||||
@ -633,16 +660,20 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
return doc.html();
|
return doc.html();
|
||||||
}
|
}
|
||||||
|
|
||||||
private static class AttachmentsChildren extends Children.Keys<AbstractFile> {
|
|
||||||
|
/**
|
||||||
|
* Creates child nodes for message attachments.
|
||||||
|
*/
|
||||||
|
private static class AttachmentsChildren extends Children.Keys<Attachment> {
|
||||||
|
|
||||||
private final Set<AbstractFile> attachments;
|
private final Set<Attachment> attachments;
|
||||||
|
|
||||||
AttachmentsChildren(Set<AbstractFile> attachments) {
|
AttachmentsChildren(Set<Attachment> attachments) {
|
||||||
this.attachments = attachments;
|
this.attachments = attachments;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
protected Node[] createNodes(AbstractFile t) {
|
protected Node[] createNodes(Attachment t) {
|
||||||
return new Node[]{new AttachmentNode(t)};
|
return new Node[]{new AttachmentNode(t)};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -652,40 +683,4 @@ public class MessageContentViewer extends javax.swing.JPanel implements DataCont
|
|||||||
setKeys(attachments);
|
setKeys(attachments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Extension of FileNode customized for viewing attachments in the
|
|
||||||
* MessageContentViewer. It overrides createSheet() to customize what
|
|
||||||
* properties are shown in the table, and could also override getActions(),
|
|
||||||
* getPreferedAction(), etc.
|
|
||||||
*/
|
|
||||||
private static class AttachmentNode extends FileNode {
|
|
||||||
|
|
||||||
AttachmentNode(AbstractFile file) {
|
|
||||||
super(file, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
protected Sheet createSheet() {
|
|
||||||
Sheet sheet = super.createSheet();
|
|
||||||
Set<String> keepProps = new HashSet<>(Arrays.asList(
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.nameColLbl"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.score.name"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.comment.name"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.createSheet.count.name"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.sizeColLbl"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.mimeType"),
|
|
||||||
NbBundle.getMessage(AbstractAbstractFileNode.class, "AbstractAbstractFileNode.knownColLbl")));
|
|
||||||
|
|
||||||
//Remove all other props except for the ones above
|
|
||||||
Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
|
|
||||||
for (Property<?> p : sheetSet.getProperties()) {
|
|
||||||
if (!keepProps.contains(p.getName())) {
|
|
||||||
sheetSet.remove(p.getName());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return sheet;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
207
Core/src/org/sleuthkit/autopsy/datamodel/AttachmentNode.java
Normal file
207
Core/src/org/sleuthkit/autopsy/datamodel/AttachmentNode.java
Normal file
@ -0,0 +1,207 @@
|
|||||||
|
/*
|
||||||
|
* Autopsy Forensic Browser
|
||||||
|
*
|
||||||
|
* Copyright 2017-2019 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.Arrays;
|
||||||
|
import java.util.Collection;
|
||||||
|
import java.util.HashSet;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import javax.swing.Action;
|
||||||
|
import org.apache.commons.lang3.StringUtils;
|
||||||
|
import org.openide.nodes.Children;
|
||||||
|
import org.openide.nodes.Sheet;
|
||||||
|
import org.openide.util.Lookup;
|
||||||
|
import org.openide.util.NbBundle;
|
||||||
|
import org.openide.util.Utilities;
|
||||||
|
import org.openide.util.lookup.Lookups;
|
||||||
|
import org.sleuthkit.autopsy.actions.AddContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.actions.DeleteFileContentTagAction;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.Case;
|
||||||
|
import org.sleuthkit.autopsy.casemodule.NoCurrentCaseException;
|
||||||
|
import org.sleuthkit.autopsy.contentviewers.MessageContentViewer;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.ContextMenuExtensionPoint;
|
||||||
|
import org.sleuthkit.autopsy.coreutils.Logger;
|
||||||
|
import static org.sleuthkit.autopsy.datamodel.FileNode.getIconForFileType;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExportCSVAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExternalViewerShortcutAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ExtractAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.NewWindowViewAction;
|
||||||
|
import org.sleuthkit.autopsy.directorytree.ViewContextAction;
|
||||||
|
import org.sleuthkit.autopsy.timeline.actions.ViewFileInTimelineAction;
|
||||||
|
import org.sleuthkit.datamodel.AbstractFile;
|
||||||
|
import org.sleuthkit.datamodel.TskException;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.Attachment;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.FileAttachment;
|
||||||
|
import org.sleuthkit.datamodel.blackboardutils.URLAttachment;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Node for a message attachment.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
public final class AttachmentNode extends DisplayableItemNode {
|
||||||
|
|
||||||
|
private static final Logger LOGGER = Logger.getLogger(MessageContentViewer.class.getName());
|
||||||
|
|
||||||
|
private final Attachment attachment;
|
||||||
|
private final AbstractFile attachmentFile;
|
||||||
|
|
||||||
|
public AttachmentNode(Attachment attachment) {
|
||||||
|
|
||||||
|
super(Children.LEAF, createLookup(attachment));
|
||||||
|
|
||||||
|
super.setName(attachment.getLocation());
|
||||||
|
super.setDisplayName(attachment.getLocation()); // SET NODE DISPLAY NAME, I.E., TEXT IN FIRST TABLE CELL
|
||||||
|
|
||||||
|
this.attachment = attachment;
|
||||||
|
Long attachmentObjId = attachment.getObjId();
|
||||||
|
AbstractFile attchmentAbstractFile = null;
|
||||||
|
|
||||||
|
if (attachmentObjId != null && attachmentObjId > 0) {
|
||||||
|
try {
|
||||||
|
attchmentAbstractFile = Case.getCurrentCaseThrows().getSleuthkitCase().getAbstractFileById(attachmentObjId);
|
||||||
|
} catch (TskException | NoCurrentCaseException ex) {
|
||||||
|
LOGGER.log(Level.WARNING, "Error loading attachment file with object id " + attachmentObjId, ex); //NON-NLS
|
||||||
|
}
|
||||||
|
}
|
||||||
|
attachmentFile = attchmentAbstractFile;
|
||||||
|
|
||||||
|
// set the icon for node
|
||||||
|
setIcon();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
@NbBundle.Messages({
|
||||||
|
"AttachmentNode.getActions.viewFileInDir.text=View File in Directory",
|
||||||
|
"AttachmentNode.getActions.viewInNewWin.text=View in New Window",
|
||||||
|
"AttachmentNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E",
|
||||||
|
"AttachmentNode.getActions.searchFilesSameMD5.text=Search for files with the same MD5 hash"})
|
||||||
|
public Action[] getActions(boolean context) {
|
||||||
|
|
||||||
|
List<Action> actionsList = new ArrayList<>();
|
||||||
|
actionsList.addAll(Arrays.asList(super.getActions(true)));
|
||||||
|
|
||||||
|
// If there is an attachment file
|
||||||
|
if (this.attachmentFile != null) {
|
||||||
|
actionsList.add(new ViewContextAction(Bundle.AttachmentNode_getActions_viewFileInDir_text(), this.attachmentFile));
|
||||||
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
|
actionsList.add(new NewWindowViewAction(Bundle.AttachmentNode_getActions_viewInNewWin_text(), this));
|
||||||
|
final Collection<AbstractFile> selectedFilesList
|
||||||
|
= new HashSet<>(Utilities.actionsGlobalContext().lookupAll(AbstractFile.class));
|
||||||
|
if (selectedFilesList.size() == 1) {
|
||||||
|
actionsList.add(new ExternalViewerAction(
|
||||||
|
Bundle.AttachmentNode_getActions_openInExtViewer_text(), this));
|
||||||
|
} else {
|
||||||
|
actionsList.add(ExternalViewerShortcutAction.getInstance());
|
||||||
|
}
|
||||||
|
actionsList.add(ViewFileInTimelineAction.createViewFileAction(this.attachmentFile));
|
||||||
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
|
actionsList.add(ExtractAction.getInstance());
|
||||||
|
actionsList.add(ExportCSVAction.getInstance());
|
||||||
|
actionsList.add(null); // Creates an item separator
|
||||||
|
|
||||||
|
actionsList.add(AddContentTagAction.getInstance());
|
||||||
|
if (1 == selectedFilesList.size()) {
|
||||||
|
actionsList.add(DeleteFileContentTagAction.getInstance());
|
||||||
|
}
|
||||||
|
actionsList.addAll(ContextMenuExtensionPoint.getActions());
|
||||||
|
|
||||||
|
}
|
||||||
|
return actionsList.toArray(new Action[0]);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected Sheet createSheet() {
|
||||||
|
|
||||||
|
// Create a new property sheet.
|
||||||
|
Sheet sheet = new Sheet();
|
||||||
|
Sheet.Set sheetSet = Sheet.createPropertiesSet();
|
||||||
|
sheet.put(sheetSet);
|
||||||
|
|
||||||
|
sheetSet.put(new NodeProperty<>("Location", "Location", "", this.attachment.getLocation()));
|
||||||
|
|
||||||
|
if (attachmentFile != null) {
|
||||||
|
long size = attachmentFile.getSize();
|
||||||
|
String mimeType = attachmentFile.getMIMEType();
|
||||||
|
|
||||||
|
// @TODO Vik-5762: get SCO Columns
|
||||||
|
|
||||||
|
sheetSet.put(new NodeProperty<>("Size", "Size", "", size));
|
||||||
|
if (StringUtils.isNotEmpty(mimeType)) {
|
||||||
|
sheetSet.put(new NodeProperty<>("Mime type", "Mime type", "", mimeType));
|
||||||
|
}
|
||||||
|
sheetSet.put(new NodeProperty<>("Known", "Known", "", attachmentFile.getKnown().getName()));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sheet;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
|
||||||
|
return visitor.visit(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isLeafTypeNode() {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String getItemType() {
|
||||||
|
return getClass().getName();
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Lookup createLookup(Attachment attachment) {
|
||||||
|
Long attachmentObjId = attachment.getObjId();
|
||||||
|
if (attachmentObjId != null && attachmentObjId > 0) {
|
||||||
|
AbstractFile attachmentFile = null;
|
||||||
|
try {
|
||||||
|
attachmentFile = Case.getCurrentCaseThrows().getSleuthkitCase().getAbstractFileById(attachmentObjId);
|
||||||
|
if (attachmentFile != null) {
|
||||||
|
return Lookups.fixed(attachment, attachmentFile);
|
||||||
|
} else {
|
||||||
|
return Lookups.fixed(attachment);
|
||||||
|
}
|
||||||
|
} catch (TskException | NoCurrentCaseException ex) {
|
||||||
|
return Lookups.fixed(attachment);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return Lookups.fixed(attachment);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Set the icon based on attachment type
|
||||||
|
*/
|
||||||
|
private void setIcon() {
|
||||||
|
if (attachmentFile != null) {
|
||||||
|
this.setIconBaseWithExtension(getIconForFileType(attachmentFile));
|
||||||
|
} else if (attachment instanceof FileAttachment) {
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/document-question-16.png");
|
||||||
|
} else if (attachment instanceof URLAttachment) {
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/url-16.png");
|
||||||
|
} else {
|
||||||
|
this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-icon-deleted.png");
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -43,6 +43,11 @@ ArtifactStringContent.attrsTableHeader.type=Type
|
|||||||
ArtifactStringContent.attrsTableHeader.value=Value
|
ArtifactStringContent.attrsTableHeader.value=Value
|
||||||
ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
ArtifactStringContent.failedToGetAttributes.message=Failed to get some or all attributes from case database
|
||||||
ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database
|
ArtifactStringContent.failedToGetSourcePath.message=Failed to get source file path from case database
|
||||||
|
AttachmentNode.getActions.openInExtViewer.text=Open in External Viewer Ctrl+E
|
||||||
|
AttachmentNode.getActions.searchFilesSameMD5.text=Search for files with the same MD5 hash
|
||||||
|
AttachmentNode.getActions.viewFileInDir.text=View File in Directory
|
||||||
|
AttachmentNode.getActions.viewInNewWin.text=View in New Window
|
||||||
|
# {0} - node name
|
||||||
BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0}
|
BaseChildFactory.NoSuchEventBusException.message=No event bus for node: {0}
|
||||||
BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details
|
BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details
|
||||||
BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details
|
BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details
|
||||||
|
@ -186,6 +186,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
|
|
||||||
T visit(InterestingHits.InterestingItemTypeNode aThis);
|
T visit(InterestingHits.InterestingItemTypeNode aThis);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Attachments
|
||||||
|
*/
|
||||||
|
T visit(AttachmentNode node);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Visitor with an implementable default behavior for all types. Override
|
* Visitor with an implementable default behavior for all types. Override
|
||||||
* specific visit types to not use the default behavior.
|
* specific visit types to not use the default behavior.
|
||||||
@ -522,5 +527,11 @@ public interface DisplayableItemNodeVisitor<T> {
|
|||||||
public T visit(Accounts.DefaultAccountTypeNode node) {
|
public T visit(Accounts.DefaultAccountTypeNode node) {
|
||||||
return defaultVisit(node);
|
return defaultVisit(node);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public T visit(AttachmentNode node) {
|
||||||
|
return defaultVisit(node);
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
BIN
Core/src/org/sleuthkit/autopsy/images/document-question-16.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/document-question-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 269 B |
BIN
Core/src/org/sleuthkit/autopsy/images/url-16.png
Normal file
BIN
Core/src/org/sleuthkit/autopsy/images/url-16.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 753 B |
Loading…
x
Reference in New Issue
Block a user