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;
69 import org.
sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
71 import org.
sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
91 private static Cache<Long, Content>
contentCache = CacheBuilder.newBuilder()
92 .expireAfterWrite(1, TimeUnit.MINUTES).
108 BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
109 BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
110 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
111 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(),};
117 BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
119 private final PropertyChangeListener
pcl =
new PropertyChangeListener() {
121 public void propertyChange(PropertyChangeEvent evt) {
122 String eventType = evt.getPropertyName();
125 if (event.getAddedTag().getArtifact().equals(artifact)) {
130 if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) {
135 if (event.getAddedTag().getContent().equals(associated)) {
140 if (event.getDeletedTagInfo().getContentID() == associated.getId()) {
145 if (event.getContentID() == associated.getId()) {
149 if (evt.getNewValue() == null) {
152 contentCache.invalidateAll();
166 private final PropertyChangeListener
weakPcl = WeakListeners.propertyChange(pcl, null);
182 for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
183 if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
184 this.associated = lookupContent;
189 this.
setName(Long.toString(artifact.getArtifactID()));
191 this.setIconBaseWithExtension(iconPath);
230 "BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
231 "BlackboardArtifactNode.getAction.resultErrorMessage=There was a problem getting actions for the selected result."
232 +
" The 'View Result in Timeline' action will not be available.",
233 "BlackboardArtifactNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. "
234 +
" The 'View File in Timeline' action will not be available."})
236 List<Action> actionsList =
new ArrayList<>();
237 actionsList.addAll(Arrays.asList(super.getActions(context)));
238 AbstractFile file = getLookup().lookup(AbstractFile.class);
245 }
catch (TskCoreException ex) {
246 logger.log(Level.SEVERE, MessageFormat.format(
"Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex);
247 MessageNotifyUtil.
Notify.
error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
252 AbstractFile c = findLinked(artifact);
256 }
catch (TskCoreException ex) {
257 logger.log(Level.SEVERE, MessageFormat.format(
"Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex);
258 MessageNotifyUtil.
Notify.
error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
266 return actionsList.toArray(
new Action[actionsList.size()]);
269 @NbBundle.Messages({
"# {0} - artifactDisplayName",
"BlackboardArtifactNode.displayName.artifact={0} Artifact"})
276 String displayName =
"";
282 && (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
283 || artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID())) {
285 for (BlackboardAttribute attribute : artifact.getAttributes()) {
286 if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
288 if (associatedArtifact != null) {
289 if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
290 artifact.getDisplayName();
292 displayName = NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.displayName.artifact", associatedArtifact.getDisplayName());
302 if (displayName.isEmpty() && artifact != null) {
303 displayName = artifact.getName();
318 if (associated != null) {
319 srcName = associated.getName();
325 "BlackboardArtifactNode.createSheet.artifactType.displayName=Artifact Type",
326 "BlackboardArtifactNode.createSheet.artifactType.name=Artifact Type",
327 "BlackboardArtifactNode.createSheet.artifactDetails.displayName=Artifact Details",
328 "BlackboardArtifactNode.createSheet.artifactDetails.name=Artifact Details",
329 "BlackboardArtifactNode.artifact.displayName=Artifact",
330 "BlackboardArtifactNode.createSheet.artifactMD5.displayName=MD5 Hash",
331 "BlackboardArtifactNode.createSheet.artifactMD5.name=MD5 Hash",
332 "BlackboardArtifactNode.createSheet.fileSize.name=Size",
333 "BlackboardArtifactNode.createSheet.fileSize.displayName=Size",
334 "BlackboardArtifactNode.createSheet.path.displayName=Path",
335 "BlackboardArtifactNode.createSheet.path.name=Path"})
339 Sheet sheet = super.createSheet();
342 Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
343 if (sheetSet == null) {
344 sheetSet = Sheet.createPropertiesSet();
348 Map<String, Object> map =
new LinkedHashMap<>();
352 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.srcFile.displayName"),
367 if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
369 BlackboardAttribute attribute = artifact.getAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
370 if (attribute != null) {
373 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactType.displayName"),
375 associatedArtifact.getDisplayName() +
" " + NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.artifact.displayName")));
377 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
379 associatedArtifact.getShortDescription()));
386 for (Map.Entry<String, Object> entry : map.entrySet()) {
394 if (customProperties != null) {
400 final int artifactTypeId = artifact.getArtifactTypeID();
403 if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
405 String actualMimeType =
"";
406 if (associated instanceof AbstractFile) {
407 AbstractFile af = (AbstractFile) associated;
408 ext = af.getNameExtension();
409 actualMimeType = af.getMIMEType();
410 if (actualMimeType == null) {
420 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.mimeType.displayName"),
425 if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
426 String sourcePath =
"";
428 sourcePath = associated.getUniquePath();
429 }
catch (TskCoreException ex) {
430 logger.log(Level.WARNING,
"Failed to get unique path from: {0}", associated.getName());
433 if (sourcePath.isEmpty() ==
false) {
436 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.filePath.displayName"),
441 if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
442 AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
444 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileModifiedTime.displayName"),
448 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileChangedTime.displayName"),
452 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileAccessedTime.displayName"),
456 NbBundle.getMessage(
BlackboardArtifactNode.class,
"ContentTagNode.createSheet.fileCreatedTime.displayName"),
462 associated.getSize()));
463 sheetSet.put(
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
464 Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
466 file == null ?
"" : StringUtils.defaultString(file.getMd5Hash())));
469 String dataSourceStr =
"";
471 Content dataSource = associated.getDataSource();
472 if (dataSource != null) {
473 dataSourceStr = dataSource.getName();
477 }
catch (TskCoreException ex) {
478 logger.log(Level.WARNING,
"Failed to get image name from {0}", associated.getName());
481 if (dataSourceStr.isEmpty() ==
false) {
484 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.dataSrc.displayName"),
491 if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
495 if (associated instanceof AbstractFile) {
496 AbstractFile af = (AbstractFile) associated;
499 path = af.getUniquePath();
500 }
catch (TskCoreException ex) {
501 path = af.getParentPath();
505 NbBundle.getMessage(
BlackboardArtifactNode.class,
"BlackboardArtifactNode.createSheet.fileSize.displayName"),
526 List<Tag> tags =
new ArrayList<>();
531 logger.log(Level.SEVERE,
"Failed to get tags for artifact " + artifact.getDisplayName(), ex);
544 "BlackboardArtifactNode.createSheet.tags.displayName=Tags"})
546 protected void addTagProperty(Sheet.Set sheetSet)
throws MissingResourceException {
548 List<Tag> tags =
new ArrayList<>();
553 logger.log(Level.SEVERE,
"Failed to get tags for artifact " + artifact.getDisplayName(), ex);
555 sheetSet.put(
new NodeProperty<>(
"Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
556 NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(
", "))));
570 sheetSet.put(
new NodeProperty<>(
"Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
571 NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(
", "))));
579 return correlationAttribute;
593 @NbBundle.Messages({
"BlackboardArtifactNode.createSheet.comment.name=C",
594 "BlackboardArtifactNode.createSheet.comment.displayName=C"})
597 for (Tag tag : tags) {
598 if (!StringUtils.isBlank(tag.getComment())) {
607 if (attribute != null && !StringUtils.isBlank(attribute.
getComment())) {
614 sheetSet.put(
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(),
NO_DESCR,
626 @NbBundle.Messages({
"BlackboardArtifactNode.createSheet.score.name=S",
627 "BlackboardArtifactNode.createSheet.score.displayName=S",
628 "BlackboardArtifactNode.createSheet.notableFile.description=Associated file recognized as notable.",
629 "BlackboardArtifactNode.createSheet.interestingResult.description=Result has an interesting result associated with it.",
630 "BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.",
631 "BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag.",
632 "BlackboardArtifactNode.createSheet.noScore.description=No score"})
635 String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
636 if (associated instanceof AbstractFile) {
637 if (((AbstractFile) associated).getKnown() == TskData.FileKnown.BAD) {
639 description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
645 BlackboardAttribute attr = content.getAttribute(
new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME));
648 if (hashDb.getHashSetName().equals(attr.getValueString())) {
650 description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
654 }
catch (TskCoreException ex) {
656 logger.log(Level.WARNING,
"Unable to get TSK_SET_NAME attribute for artifact of type TSK_HASHSET_HIT with artifact ID " + content.getArtifactID(), ex);
660 if (score ==
Score.
NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
662 description = Bundle.BlackboardArtifactNode_createSheet_interestingResult_description();
664 }
catch (TskCoreException ex) {
665 logger.log(Level.WARNING,
"Error getting artifacts for artifact: " + content.getName(), ex);
669 description = Bundle.BlackboardArtifactNode_createSheet_taggedItem_description();
670 for (Tag tag : tags) {
671 if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
673 description = Bundle.BlackboardArtifactNode_createSheet_notableTaggedItem_description();
678 sheetSet.put(
new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), description, score));
681 @NbBundle.Messages({
"BlackboardArtifactNode.createSheet.count.name=O",
682 "BlackboardArtifactNode.createSheet.count.displayName=O",
683 "BlackboardArtifactNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated",
684 "BlackboardArtifactNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this artifact's associated file when the column was populated",
685 "# {0} - occuranceCount",
686 "BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"})
690 String description = Bundle.BlackboardArtifactNode_createSheet_count_noCentralRepo_description();
695 description = Bundle.BlackboardArtifactNode_createSheet_count_description(count);
696 }
else if (attribute != null) {
697 description = Bundle.BlackboardArtifactNode_createSheet_count_hashLookupNotRun_description();
700 logger.log(Level.WARNING,
"Error getting count of datasources with correlation attribute", ex);
702 logger.log(Level.WARNING,
"Unable to normalize data to get count of datasources with correlation attribute", ex);
705 new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), description, count));
713 String parentName = associated.getName();
716 while ((parent = parent.getParent()) != null) {
717 parentName = parent.getName();
719 }
catch (TskCoreException ex) {
720 logger.log(Level.WARNING,
"Failed to get parent name from {0}", associated.getName());
733 if (null == customProperties) {
735 customProperties =
new ArrayList<>();
737 customProperties.add(np);
747 @SuppressWarnings(
"deprecation")
750 for (BlackboardAttribute attribute : artifact.getAttributes()) {
751 final int attributeTypeID = attribute.getAttributeType().getTypeID();
753 if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
754 || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
755 || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
756 || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
757 || attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
758 }
else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
760 }
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
762 }
else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
763 && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
771 String value = attribute.getDisplayString();
772 if (value.length() > 512) {
773 value = value.substring(0, 512);
775 map.put(attribute.getAttributeType().getDisplayName(), value);
777 map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
780 }
catch (TskCoreException ex) {
781 logger.log(Level.SEVERE,
"Getting attributes failed", ex);
794 final int attributeTypeID = attribute.getAttributeType().getTypeID();
797 if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
798 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
799 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
800 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
801 || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
802 || attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()) {
805 }
else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
807 String value = attribute.getDisplayString();
808 if (value.length() > 160) {
809 value = value.substring(0, 160) +
"...";
811 map.put(attribute.getAttributeType().getDisplayName(), value);
812 }
else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
815 map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
822 return visitor.
visit(
this);
835 final long objectID = artifact.getObjectID();
837 Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
838 if (content == null) {
839 return Lookups.fixed(artifact);
841 return Lookups.fixed(artifact, content);
843 }
catch (ExecutionException ex) {
844 logger.log(Level.WARNING,
"Getting associated content for artifact failed", ex);
845 return Lookups.fixed(artifact);
856 return getClass().getName();
860 public <T> T accept(ContentNodeVisitor<T> visitor) {
861 return visitor.visit(
this);
final void addTagProperty(Sheet.Set sheetSet, List< Tag > tags)
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
String getCorrelationValue()
T visit(DataSourcesNode in)
Action[] getActions(boolean context)
final void addScoreProperty(Sheet.Set sheetSet, List< Tag > tags)
Type getCorrelationType()
static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file)
static final Set< Case.Events > CASE_EVENTS_OF_INTEREST
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
TagsManager getTagsManager()
synchronized List< HashDb > getKnownBadFileHashSets()
static EamDb getInstance()
List< NodeProperty<?extends Object > > customProperties
static synchronized HashDbManager getInstance()
static CorrelationAttributeInstance getInstanceFromContent(Content content)
final List< Tag > getAllTagsFromDatabase()
String getRootParentName()
final BlackboardArtifact artifact
void addEmailMsgProperty(Map< String, Object > map, BlackboardAttribute attribute)
final void addCommentProperty(Sheet.Set sheetSet, List< Tag > tags, CorrelationAttributeInstance attribute)
final CorrelationAttributeInstance getCorrelationAttributeInstance()
SleuthkitCase getSleuthkitCase()
final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute)
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)
static boolean hideCentralRepoCommentsAndOccurrences()
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