19 package org.sleuthkit.autopsy.datamodel;
21 import com.google.common.cache.Cache;
22 import com.google.common.cache.CacheBuilder;
23 import java.beans.PropertyChangeEvent;
24 import java.beans.PropertyChangeListener;
25 import java.text.MessageFormat;
26 import java.util.ArrayList;
27 import java.util.Arrays;
28 import java.util.EnumSet;
29 import java.util.LinkedHashMap;
30 import java.util.List;
32 import java.util.MissingResourceException;
34 import java.util.concurrent.ExecutionException;
35 import java.util.concurrent.TimeUnit;
36 import java.util.logging.Level;
37 import java.util.stream.Collectors;
38 import javax.swing.Action;
39 import org.apache.commons.lang3.StringUtils;
40 import org.openide.nodes.Sheet;
41 import org.openide.util.Lookup;
42 import org.openide.util.NbBundle;
43 import org.openide.util.WeakListeners;
44 import org.openide.util.lookup.Lookups;
60 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
62 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
80 private static Cache<Long, Content>
contentCache = CacheBuilder.newBuilder()
81 .expireAfterWrite(1, TimeUnit.MINUTES).
97 BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
98 BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
99 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
100 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(),};
106 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
108 private final PropertyChangeListener
pcl =
new PropertyChangeListener() {
110 public void propertyChange(PropertyChangeEvent evt) {
111 String eventType = evt.getPropertyName();
114 if (event.getAddedTag().getArtifact().equals(artifact)) {
119 if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) {
124 if (event.getAddedTag().getContent().equals(associated)) {
129 if (event.getDeletedTagInfo().getContentID() == associated.getId()) {
133 if (evt.getNewValue() == null) {
136 contentCache.invalidateAll();
150 private final PropertyChangeListener
weakPcl = WeakListeners.propertyChange(pcl, null);
166 for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
167 if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
168 this.associated = lookupContent;
173 this.
setName(Long.toString(artifact.getArtifactID()));
175 this.setIconBaseWithExtension(iconPath);
214 "BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
215 "BlackboardArtifactNode.getAction.resultErrorMessage=There was a problem getting actions for the selected result."
216 +
" The 'View Result in Timeline' action will not be available.",
217 "BlackboardArtifactNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. "
218 +
" The 'View File in Timeline' action will not be available."})
220 List<Action> actionsList =
new ArrayList<>();
221 actionsList.addAll(Arrays.asList(super.getActions(context)));
222 AbstractFile file = getLookup().lookup(AbstractFile.class);
234 }
catch (TskCoreException ex) {
235 logger.log(Level.SEVERE, MessageFormat.format(
"Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex);
236 MessageNotifyUtil.
Notify.
error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
241 AbstractFile c = findLinked(artifact);
245 }
catch (TskCoreException ex) {
246 logger.log(Level.SEVERE, MessageFormat.format(
"Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex);
247 MessageNotifyUtil.
Notify.
error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
255 return actionsList.toArray(
new Action[actionsList.size()]);
258 @NbBundle.Messages({
"# {0} - artifactDisplayName",
"BlackboardArtifactNode.displayName.artifact={0} Artifact"})
265 String displayName =
"";
271 && (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
272 || artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID())) {
274 for (BlackboardAttribute attribute : artifact.getAttributes()) {
275 if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
277 if (associatedArtifact != null) {
278 if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
279 artifact.getDisplayName();
281 displayName = NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.displayName.artifact", associatedArtifact.getDisplayName());
291 if (displayName.isEmpty() && artifact != null) {
292 displayName = artifact.getName();
307 if (associated != null) {
308 srcName = associated.getName();
314 "BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
315 "BlackboardArtifactNode.createSheet.artifactType.name=Artifact Type",
316 "BlackboardArtifactNode.createSheet.artifactDetails.displayName=Artifact Details",
317 "BlackboardArtifactNode.createSheet.artifactDetails.name=Artifact Details",
318 "BlackboardArtifactNode.artifact.displayName=Artifact",
319 "BlackboardArtifactNode.createSheet.artifactMD5.displayName=MD5 Hash",
320 "BlackboardArtifactNode.createSheet.artifactMD5.name=MD5 Hash"})
324 Sheet sheet = super.createSheet();
325 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
326 if (sheetSet == null) {
327 sheetSet = Sheet.createPropertiesSet();
331 Map<String, Object> map =
new LinkedHashMap<>();
335 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.srcFile.displayName"),
338 if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
340 BlackboardAttribute attribute = artifact.getAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
341 if (attribute != null) {
344 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactType.displayName"),
346 associatedArtifact.getDisplayName() +
" " + NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.artifact.displayName")));
348 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
350 associatedArtifact.getShortDescription()));
357 for (Map.Entry<String, Object> entry : map.entrySet()) {
365 if (customProperties != null) {
371 final int artifactTypeId = artifact.getArtifactTypeID();
374 if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
376 String actualMimeType =
"";
377 if (associated instanceof AbstractFile) {
378 AbstractFile af = (AbstractFile) associated;
379 ext = af.getNameExtension();
380 actualMimeType = af.getMIMEType();
381 if (actualMimeType == null) {
391 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.mimeType.displayName"),
396 if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
397 String sourcePath =
"";
399 sourcePath = associated.getUniquePath();
400 }
catch (TskCoreException ex) {
401 logger.log(Level.WARNING,
"Failed to get unique path from: {0}", associated.getName());
404 if (sourcePath.isEmpty() ==
false) {
407 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.filePath.displayName"),
412 if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
413 AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
415 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileModifiedTime.displayName"),
419 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileChangedTime.displayName"),
423 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileAccessedTime.displayName"),
427 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileCreatedTime.displayName"),
433 associated.getSize()));
434 sheetSet.put(
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
435 Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
437 file == null ?
"" : StringUtils.defaultString(file.getMd5Hash())));
440 String dataSourceStr =
"";
442 Content dataSource = associated.getDataSource();
443 if (dataSource != null) {
444 dataSourceStr = dataSource.getName();
448 }
catch (TskCoreException ex) {
449 logger.log(Level.WARNING,
"Failed to get image name from {0}", associated.getName());
452 if (dataSourceStr.isEmpty() ==
false) {
455 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.dataSrc.displayName"),
474 "BlackboardArtifactNode.createSheet.tags.displayName=Tags"})
475 protected void addTagProperty(Sheet.Set sheetSet)
throws MissingResourceException {
477 List<Tag> tags =
new ArrayList<>();
482 logger.log(Level.SEVERE,
"Failed to get tags for artifact " + artifact.getDisplayName(), ex);
484 sheetSet.put(
new NodeProperty<>(
"Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
485 NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(
", "))));
493 String parentName = associated.getName();
496 while ((parent = parent.getParent()) != null) {
497 parentName = parent.getName();
499 }
catch (TskCoreException ex) {
500 logger.log(Level.WARNING,
"Failed to get parent name from {0}", associated.getName());
513 if (null == customProperties) {
515 customProperties =
new ArrayList<>();
517 customProperties.add(np);
527 @SuppressWarnings(
"deprecation")
530 for (BlackboardAttribute attribute : artifact.getAttributes()) {
531 final int attributeTypeID = attribute.getAttributeType().getTypeID();
533 if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
534 || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
535 || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
536 || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
537 || attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
538 }
else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
540 }
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
542 }
else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
543 && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
551 String value = attribute.getDisplayString();
552 if (value.length() > 512) {
553 value = value.substring(0, 512);
555 map.put(attribute.getAttributeType().getDisplayName(), value);
557 map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
560 }
catch (TskCoreException ex) {
561 logger.log(Level.SEVERE,
"Getting attributes failed", ex);
574 final int attributeTypeID = attribute.getAttributeType().getTypeID();
577 if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
578 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
579 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
580 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
581 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
582 || attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()) {
585 }
else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
587 String value = attribute.getDisplayString();
588 if (value.length() > 160) {
589 value = value.substring(0, 160) +
"...";
591 map.put(attribute.getAttributeType().getDisplayName(), value);
592 }
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
595 map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
602 return visitor.
visit(
this);
615 final long objectID = artifact.getObjectID();
617 Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
618 if (content == null) {
619 return Lookups.fixed(artifact);
621 return Lookups.fixed(artifact, content);
623 }
catch (ExecutionException ex) {
624 logger.log(Level.WARNING,
"Getting associated content for artifact failed", ex);
625 return Lookups.fixed(artifact);
636 return getClass().getName();
640 public <T> T accept(ContentNodeVisitor<T> visitor) {
641 return visitor.visit(
this);
void addTagProperty(Sheet.Set sheetSet)
void fillPropertyMap(Map< String, Object > map, BlackboardArtifact artifact)
static String getStringTime(long epochSeconds, TimeZone tzone)
static boolean hasSupportedTimeStamp(BlackboardArtifact artifact)
final PropertyChangeListener weakPcl
static Cache< Long, Content > contentCache
void setName(String name)
final PropertyChangeListener pcl
BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath)
static boolean useCentralRepo()
static Lookup createLookup(BlackboardArtifact artifact)
static final String NO_DESCR
static final Integer[] SHOW_FILE_METADATA
T visit(DataSourcesNode in)
Action[] getActions(boolean context)
static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
TagsManager getTagsManager()
List< NodeProperty<?extends Object > > customProperties
String getRootParentName()
final BlackboardArtifact artifact
void addEmailMsgProperty(Map< String, Object > map, BlackboardAttribute attribute)
SleuthkitCase getSleuthkitCase()
BLACKBOARD_ARTIFACT_TAG_ADDED
static final Logger logger
static void error(String title, String message)
BlackboardArtifact getArtifact()
synchronized static Logger getLogger(String name)
static Case getCurrentCaseThrows()
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
void addNodeProperty(NodeProperty<?> np)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
BlackboardArtifactNode(BlackboardArtifact artifact)
static final Integer[] SHOW_UNIQUE_PATH
static ViewFileInTimelineAction createViewFileAction(AbstractFile file)
BLACKBOARD_ARTIFACT_TAG_DELETED