Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
BlackboardArtifactNode.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2011-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.datamodel;
20 
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.lang.ref.WeakReference;
26 import java.text.MessageFormat;
27 import java.util.ArrayList;
28 import java.util.Arrays;
29 import java.util.EnumSet;
30 import java.util.LinkedHashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.MissingResourceException;
34 import java.util.Set;
35 import java.util.concurrent.ExecutionException;
36 import java.util.concurrent.TimeUnit;
37 import java.util.logging.Level;
38 import java.util.stream.Collectors;
39 import javax.swing.Action;
40 import org.apache.commons.lang3.StringUtils;
41 import org.apache.commons.lang3.tuple.Pair;
42 import org.openide.nodes.Sheet;
43 import org.openide.util.Lookup;
44 import org.openide.util.NbBundle;
45 import org.openide.util.WeakListeners;
46 import org.openide.util.lookup.Lookups;
67 import static org.sleuthkit.autopsy.datamodel.AbstractContentNode.backgroundTasksPool;
71 import org.sleuthkit.datamodel.AbstractFile;
72 import org.sleuthkit.datamodel.BlackboardArtifact;
73 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
74 import org.sleuthkit.datamodel.BlackboardAttribute;
75 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
76 import org.sleuthkit.datamodel.Content;
77 import org.sleuthkit.datamodel.Tag;
78 import org.sleuthkit.datamodel.TskCoreException;
79 import org.sleuthkit.datamodel.TskData;
80 
85 public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
86 
87  private static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
94 
95  private static Cache<Long, Content> contentCache = CacheBuilder.newBuilder()
96  .expireAfterWrite(1, TimeUnit.MINUTES).
97  build();
98 
99  private final BlackboardArtifact artifact;
100  private Content associated = null;
101 
102  private List<NodeProperty<? extends Object>> customProperties;
103 
104  /*
105  * Artifact types which should have the full unique path of the associated
106  * content as a property.
107  */
108  private static final Integer[] SHOW_UNIQUE_PATH = new Integer[]{
109  BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
110  BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
111  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),
112  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID(),};
113 
114  // TODO (RC): This is an unattractive alternative to subclassing BlackboardArtifactNode,
115  // cut from the same cloth as the equally unattractive SHOW_UNIQUE_PATH array
116  // above. It should be removed when and if the subclassing is implemented.
117  private static final Integer[] SHOW_FILE_METADATA = new Integer[]{
118  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
119 
120  private final PropertyChangeListener pcl = new PropertyChangeListener() {
121  @Override
122  public void propertyChange(PropertyChangeEvent evt) {
123  String eventType = evt.getPropertyName();
124  if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString())) {
126  if (event.getAddedTag().getArtifact().equals(artifact)) {
127  updateSheet();
128  }
129  } else if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString())) {
131  if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) {
132  updateSheet();
133  }
134  } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
136  if (event.getAddedTag().getContent().equals(associated)) {
137  updateSheet();
138  }
139  } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
141  if (event.getDeletedTagInfo().getContentID() == associated.getId()) {
142  updateSheet();
143  }
144  } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
146  if (event.getContentID() == associated.getId()) {
147  updateSheet();
148  }
149  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
150  if (evt.getNewValue() == null) {
151  // case was closed. Remove listeners so that we don't get called with a stale case handle
152  removeListeners();
153  contentCache.invalidateAll();
154  }
155  } else if (eventType.equals(NodeSpecificEvents.SCO_AVAILABLE.toString()) && !UserPreferences.getHideSCOColumns()) {
156  SCOData scoData = (SCOData) evt.getNewValue();
157  if (scoData.getScoreAndDescription() != null) {
158  updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoData.getScoreAndDescription().getRight(), scoData.getScoreAndDescription().getLeft()));
159  }
160  if (scoData.getComment() != null) {
161  updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR, scoData.getComment()));
162  }
163  if (scoData.getCountAndDescription() != null) {
164  updateSheet(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), scoData.getCountAndDescription().getRight(), scoData.getCountAndDescription().getLeft()));
165  }
166  }
167  }
168  };
169 
178  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
179 
188  public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
189  super(artifact, createLookup(artifact));
190 
191  this.artifact = artifact;
192 
193  // Look for associated Content i.e. the source file for the artifact
194  for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
195  if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
196  this.associated = lookupContent;
197  break;
198  }
199  }
200 
201  this.setName(Long.toString(artifact.getArtifactID()));
202  this.setDisplayName();
203  this.setIconBaseWithExtension(iconPath);
205  }
206 
213  public BlackboardArtifactNode(BlackboardArtifact artifact) {
214  this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID()));
215  }
216 
226  @Override
227  protected void finalize() throws Throwable {
228  super.finalize();
229  removeListeners();
230  }
231 
232  private void removeListeners() {
234  }
235 
236  public BlackboardArtifact getArtifact() {
237  return this.artifact;
238  }
239 
240  @Override
241  @NbBundle.Messages({
242  "BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
243  "BlackboardArtifactNode.getAction.resultErrorMessage=There was a problem getting actions for the selected result."
244  + " The 'View Result in Timeline' action will not be available.",
245  "BlackboardArtifactNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. "
246  + " The 'View File in Timeline' action will not be available."})
247  public Action[] getActions(boolean context) {
248  List<Action> actionsList = new ArrayList<>();
249  actionsList.addAll(Arrays.asList(super.getActions(context)));
250  AbstractFile file = getLookup().lookup(AbstractFile.class);
251 
252  //if this artifact has a time stamp add the action to view it in the timeline
253  try {
255  actionsList.add(new ViewArtifactInTimelineAction(artifact));
256  }
257  } catch (TskCoreException ex) {
258  logger.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
259  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
260  }
261 
262  // if the artifact links to another file, add an action to go to that file
263  try {
264  AbstractFile c = findLinked(artifact);
265  if (c != null) {
267  }
268  } catch (TskCoreException ex) {
269  logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
270  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
271  }
272 
273  //if the artifact has associated content, add the action to view the content in the timeline
274  if (null != file) {
276  }
277 
278  return actionsList.toArray(new Action[actionsList.size()]);
279  }
280 
281  @NbBundle.Messages({"# {0} - artifactDisplayName", "BlackboardArtifactNode.displayName.artifact={0} Artifact"})
287  private void setDisplayName() {
288  String displayName = ""; //NON-NLS
289 
290  // If this is a node for a keyword hit on an artifact, we set the
291  // display name to be the artifact type name followed by " Artifact"
292  // e.g. "Messages Artifact".
293  if (artifact != null
294  && (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
295  || artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID())) {
296  try {
297  for (BlackboardAttribute attribute : artifact.getAttributes()) {
298  if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
299  BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
300  if (associatedArtifact != null) {
301  if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
302  artifact.getDisplayName();
303  } else {
304  displayName = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.displayName.artifact", associatedArtifact.getDisplayName());
305  }
306  }
307  }
308  }
309  } catch (TskCoreException | NoCurrentCaseException ex) {
310  // Do nothing since the display name will be set to the file name.
311  }
312  }
313 
314  if (displayName.isEmpty() && artifact != null) {
315  displayName = artifact.getName();
316  }
317 
318  this.setDisplayName(displayName);
319 
320  }
321 
327  public String getSourceName() {
328 
329  String srcName = "";
330  if (associated != null) {
331  srcName = associated.getName();
332  }
333  return srcName;
334  }
335 
336  @NbBundle.Messages({
337  "BlackboardArtifactNode.createSheet.artifactType.displayName=Result Type",
338  "BlackboardArtifactNode.createSheet.artifactType.name=Result Type",
339  "BlackboardArtifactNode.createSheet.artifactDetails.displayName=Result Details",
340  "BlackboardArtifactNode.createSheet.artifactDetails.name=Result Details",
341  "BlackboardArtifactNode.createSheet.artifactMD5.displayName=MD5 Hash",
342  "BlackboardArtifactNode.createSheet.artifactMD5.name=MD5 Hash",
343  "BlackboardArtifactNode.createSheet.fileSize.name=Size",
344  "BlackboardArtifactNode.createSheet.fileSize.displayName=Size",
345  "BlackboardArtifactNode.createSheet.path.displayName=Path",
346  "BlackboardArtifactNode.createSheet.path.name=Path"})
347 
348  @Override
349  protected Sheet createSheet() {
350  Sheet sheet = super.createSheet();
351  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
352  if (sheetSet == null) {
353  sheetSet = Sheet.createPropertiesSet();
354  sheet.put(sheetSet);
355  }
356 
357  Map<String, Object> map = new LinkedHashMap<>();
358  fillPropertyMap(map, artifact);
359 
360  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"),
361  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
362  NO_DESCR,
363  this.getSourceName()));
364 
365  // Create place holders for S C O
367  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), VALUE_LOADING, ""));
368  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), VALUE_LOADING, ""));
369  if (EamDb.isEnabled()) {
370  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), VALUE_LOADING, ""));
371  }
372  // Get the SCO columns data in a background task
373  backgroundTasksPool.submit(new GetSCOTask(
374  new WeakReference<>(this), weakPcl));
375  }
376 
377  if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
378  try {
379  BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
380  if (attribute != null) {
381  BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
382  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"),
383  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"),
384  NO_DESCR,
385  associatedArtifact.getDisplayName()));
386  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"),
387  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
388  NO_DESCR,
389  associatedArtifact.getShortDescription()));
390  }
391  } catch (TskCoreException | NoCurrentCaseException ex) {
392  // Do nothing since the display name will be set to the file name.
393  }
394  }
395 
396  for (Map.Entry<String, Object> entry : map.entrySet()) {
397  sheetSet.put(new NodeProperty<>(entry.getKey(),
398  entry.getKey(),
399  NO_DESCR,
400  entry.getValue()));
401  }
402 
403  //append custom node properties
404  if (customProperties != null) {
405  for (NodeProperty<? extends Object> np : customProperties) {
406  sheetSet.put(np);
407  }
408  }
409 
410  final int artifactTypeId = artifact.getArtifactTypeID();
411 
412  // If mismatch, add props for extension and file type
413  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
414  String ext = ""; //NON-NLS
415  String actualMimeType = ""; //NON-NLS
416  if (associated instanceof AbstractFile) {
417  AbstractFile af = (AbstractFile) associated;
418  ext = af.getNameExtension();
419  actualMimeType = af.getMIMEType();
420  if (actualMimeType == null) {
421  actualMimeType = ""; //NON-NLS
422  }
423  }
424  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
425  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
426  NO_DESCR,
427  ext));
428  sheetSet.put(new NodeProperty<>(
429  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"),
430  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"),
431  NO_DESCR,
432  actualMimeType));
433  }
434 
435  if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
436  String sourcePath = ""; //NON-NLS
437  try {
438  sourcePath = associated.getUniquePath();
439  } catch (TskCoreException ex) {
440  logger.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
441  }
442 
443  if (sourcePath.isEmpty() == false) {
444  sheetSet.put(new NodeProperty<>(
445  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"),
446  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"),
447  NO_DESCR,
448  sourcePath));
449  }
450 
451  if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
452  AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
453  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
454  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
455  "",
456  file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file)));
457  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
458  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
459  "",
460  file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file)));
461  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
462  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
463  "",
464  file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file)));
465  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
466  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
467  "",
468  file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file)));
469  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
470  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
471  "",
472  associated.getSize()));
473  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
474  Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
475  "",
476  file == null ? "" : StringUtils.defaultString(file.getMd5Hash())));
477  }
478  } else {
479  String dataSourceStr = "";
480  try {
481  Content dataSource = associated.getDataSource();
482  if (dataSource != null) {
483  dataSourceStr = dataSource.getName();
484  } else {
485  dataSourceStr = getRootParentName();
486  }
487  } catch (TskCoreException ex) {
488  logger.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
489  }
490 
491  if (dataSourceStr.isEmpty() == false) {
492  sheetSet.put(new NodeProperty<>(
493  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"),
494  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
495  NO_DESCR,
496  dataSourceStr));
497  }
498  }
499 
500  // If EXIF, add props for file size and path
501  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
502 
503  long size = 0;
504  String path = ""; //NON-NLS
505  if (associated instanceof AbstractFile) {
506  AbstractFile af = (AbstractFile) associated;
507  size = af.getSize();
508  try {
509  path = af.getUniquePath();
510  } catch (TskCoreException ex) {
511  path = af.getParentPath();
512  }
513  }
514  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
515  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"),
516  NO_DESCR,
517  size));
518  sheetSet.put(new NodeProperty<>(
519  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
520  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
521  NO_DESCR,
522  path));
523  }
524 
525  return sheet;
526  }
527 
535  @Override
536  protected final List<Tag> getAllTagsFromDatabase() {
537  List<Tag> tags = new ArrayList<>();
538  try {
541  } catch (TskCoreException | NoCurrentCaseException ex) {
542  logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
543  }
544  return tags;
545  }
546 
554  @NbBundle.Messages({
555  "BlackboardArtifactNode.createSheet.tags.displayName=Tags"})
556  @Deprecated
557  protected void addTagProperty(Sheet.Set sheetSet) throws MissingResourceException {
558  // add properties for tags
559  List<Tag> tags = new ArrayList<>();
560  try {
563  } catch (TskCoreException | NoCurrentCaseException ex) {
564  logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
565  }
566  sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
567  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
568  }
569 
579  @Deprecated
580  protected final void addTagProperty(Sheet.Set sheetSet, List<Tag> tags) {
581  sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
582  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
583  }
584 
591  @Override
593  CorrelationAttributeInstance correlationAttribute = null;
594  if (EamDb.isEnabled()) {
595  correlationAttribute = EamArtifactUtil.getInstanceFromContent(associated);
596  }
597  return correlationAttribute;
598  }
599 
613  @NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",
614  "BlackboardArtifactNode.createSheet.comment.displayName=C"})
615  @Deprecated
616  protected final void addCommentProperty(Sheet.Set sheetSet, List<Tag> tags, CorrelationAttributeInstance attribute) {
617  HasCommentStatus status = getCommentProperty(tags, attribute);
618  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR,
619  status));
620  }
621 
632  @Override
634 
636  for (Tag tag : tags) {
637  if (!StringUtils.isBlank(tag.getComment())) {
638  //if the tag is null or empty or contains just white space it will indicate there is not a comment
639  status = HasCommentStatus.TAG_COMMENT;
640  break;
641  }
642  }
643  //currently checks for a comment on the associated file in the central repo not the artifact itself
644  //what we want the column property to reflect should be revisted when we have added a way to comment
645  //on the artifact itself
646  if (attribute != null && !StringUtils.isBlank(attribute.getComment())) {
647  if (status == HasCommentStatus.TAG_COMMENT) {
649  } else {
650  status = HasCommentStatus.CR_COMMENT;
651  }
652  }
653  return status;
654  }
655 
666  @NbBundle.Messages({"BlackboardArtifactNode.createSheet.score.name=S",
667  "BlackboardArtifactNode.createSheet.score.displayName=S",
668  "BlackboardArtifactNode.createSheet.notableFile.description=Associated file recognized as notable.",
669  "BlackboardArtifactNode.createSheet.interestingResult.description=Result has an interesting result associated with it.",
670  "BlackboardArtifactNode.createSheet.taggedItem.description=Result or associated file has been tagged.",
671  "BlackboardArtifactNode.createSheet.notableTaggedItem.description=Result or associated file tagged with notable tag.",
672  "BlackboardArtifactNode.createSheet.noScore.description=No score"})
673  @Deprecated
674  protected final void addScorePropertyAndDescription(Sheet.Set sheetSet, List<Tag> tags) {
675  Pair<DataResultViewerTable.Score, String> scoreAndDescription = getScorePropertyAndDescription(tags);
676  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), scoreAndDescription.getRight(), scoreAndDescription.getLeft()));
677  }
678 
686  @Override
687  protected Pair<DataResultViewerTable.Score, String> getScorePropertyAndDescription(List<Tag> tags) {
688  Score score = Score.NO_SCORE;
689  String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
690  if (associated instanceof AbstractFile) {
691  if (((AbstractFile) associated).getKnown() == TskData.FileKnown.BAD) {
692  score = Score.NOTABLE_SCORE;
693  description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
694  }
695  }
696  //if the artifact being viewed is a hashhit check if the hashset is notable
697  if ((score == Score.NO_SCORE || score == Score.INTERESTING_SCORE) && content.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
698  try {
699  BlackboardAttribute attr = content.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME));
701  for (HashDbManager.HashDb hashDb : notableHashsets) {
702  if (hashDb.getHashSetName().equals(attr.getValueString())) {
703  score = Score.NOTABLE_SCORE;
704  description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
705  break;
706  }
707  }
708  } catch (TskCoreException ex) {
709  //unable to get the attribute so we can not update the status based on the attribute
710  logger.log(Level.WARNING, "Unable to get TSK_SET_NAME attribute for artifact of type TSK_HASHSET_HIT with artifact ID " + content.getArtifactID(), ex);
711  }
712  }
713  try {
714  if (score == Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
715  score = Score.INTERESTING_SCORE;
716  description = Bundle.BlackboardArtifactNode_createSheet_interestingResult_description();
717  }
718  } catch (TskCoreException ex) {
719  logger.log(Level.WARNING, "Error getting artifacts for artifact: " + content.getName(), ex);
720  }
721  if (tags.size() > 0 && (score == Score.NO_SCORE || score == Score.INTERESTING_SCORE)) {
722  score = Score.INTERESTING_SCORE;
723  description = Bundle.BlackboardArtifactNode_createSheet_taggedItem_description();
724  for (Tag tag : tags) {
725  if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
726  score = Score.NOTABLE_SCORE;
727  description = Bundle.BlackboardArtifactNode_createSheet_notableTaggedItem_description();
728  break;
729  }
730  }
731  }
732 
733  return Pair.of(score, description);
734  }
735 
746  @NbBundle.Messages({"BlackboardArtifactNode.createSheet.count.name=O",
747  "BlackboardArtifactNode.createSheet.count.displayName=O",
748  "BlackboardArtifactNode.createSheet.count.noCorrelationAttributes.description=No correlation properties found",
749  "BlackboardArtifactNode.createSheet.count.noCorrelationValues.description=Unable to find other occurrences because no value exists for the available correlation property",
750  "# {0} - occurrenceCount",
751  "# {1} - attributeType",
752  "BlackboardArtifactNode.createSheet.count.description=There were {0} datasource(s) found with occurrences of the correlation value of type {1}"})
753  @Deprecated
754  protected final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute) {
755  Pair<Long, String> countAndDescription = getCountPropertyAndDescription(attribute.getCorrelationType(), attribute.getCorrelationValue(), Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationAttributes_description());
756  sheetSet.put(
757  new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), countAndDescription.getRight(), countAndDescription.getLeft()));
758  }
759 
771  @Override
772  protected Pair<Long, String> getCountPropertyAndDescription(Type attributeType, String attributeValue, String defaultDescription) {
773  Long count = -1L;
774  String description = defaultDescription;
775  try {
776  //don't perform the query if there is no correlation value
777  if (attributeType != null && StringUtils.isNotBlank(attributeValue)) {
778  count = EamDb.getInstance().getCountUniqueCaseDataSourceTuplesHavingTypeValue(attributeType, attributeValue);
779  description = Bundle.BlackboardArtifactNode_createSheet_count_description(count, attributeType.getDisplayName());
780  } else if (attributeType != null) {
781  description = Bundle.BlackboardArtifactNode_createSheet_count_noCorrelationValues_description();
782  }
783  } catch (EamDbException ex) {
784  logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
786  logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
787  }
788  return Pair.of(count, description);
789  }
790 
791  private void updateSheet() {
792  this.setSheet(createSheet());
793  }
794 
795  private String getRootParentName() {
796  String parentName = associated.getName();
797  Content parent = associated;
798  try {
799  while ((parent = parent.getParent()) != null) {
800  parentName = parent.getName();
801  }
802  } catch (TskCoreException ex) {
803  logger.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
804  return "";
805  }
806  return parentName;
807  }
808 
816  if (null == customProperties) {
817  //lazy create the list
818  customProperties = new ArrayList<>();
819  }
820  customProperties.add(np);
821  }
822 
830  @SuppressWarnings("deprecation")
831  private void fillPropertyMap(Map<String, Object> map, BlackboardArtifact artifact) {
832  try {
833  for (BlackboardAttribute attribute : artifact.getAttributes()) {
834  final int attributeTypeID = attribute.getAttributeType().getTypeID();
835  //skip some internal attributes that user shouldn't see
836  if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
837  || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
838  || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
839  || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()
840  || attributeTypeID == ATTRIBUTE_TYPE.TSK_KEYWORD_SEARCH_TYPE.getTypeID()) {
841  } else if (artifact.getArtifactTypeID() == BlackboardArtifact.ARTIFACT_TYPE.TSK_EMAIL_MSG.getTypeID()) {
842  addEmailMsgProperty(map, attribute);
843  } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
844  map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
845  } else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
846  && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
847  /*
848  * This was added because the RegRipper output would often
849  * cause the UI to get a black line accross it and hang if
850  * you hovered over large output or selected it. This
851  * reduces the amount of data in the table. Could consider
852  * doing this for all fields in the UI.
853  */
854  String value = attribute.getDisplayString();
855  if (value.length() > 512) {
856  value = value.substring(0, 512);
857  }
858  map.put(attribute.getAttributeType().getDisplayName(), value);
859  } else {
860  map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
861  }
862  }
863  } catch (TskCoreException ex) {
864  logger.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
865  }
866  }
867 
875  private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute) {
876 
877  final int attributeTypeID = attribute.getAttributeType().getTypeID();
878 
879  // Skip certain Email msg attributes
880  if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
881  || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_HTML.getTypeID()
882  || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_RTF.getTypeID()
883  || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_BCC.getTypeID()
884  || attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CC.getTypeID()
885  || attributeTypeID == ATTRIBUTE_TYPE.TSK_HEADERS.getTypeID()) {
886 
887  // do nothing
888  } else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
889 
890  String value = attribute.getDisplayString();
891  if (value.length() > 160) {
892  value = value.substring(0, 160) + "...";
893  }
894  map.put(attribute.getAttributeType().getDisplayName(), value);
895  } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
896  map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
897  } else {
898  map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
899  }
900 
901  }
902 
903  @Override
904  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
905  return visitor.visit(this);
906  }
907 
916  private static Lookup createLookup(BlackboardArtifact artifact) {
917  // Add the content the artifact is associated with
918  final long objectID = artifact.getObjectID();
919  try {
920  Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
921  if (content == null) {
922  return Lookups.fixed(artifact);
923  } else {
924  return Lookups.fixed(artifact, content);
925  }
926  } catch (ExecutionException ex) {
927  logger.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS
928  return Lookups.fixed(artifact);
929  }
930  }
931 
932  @Override
933  public boolean isLeafTypeNode() {
934  return true;
935  }
936 
937  @Override
938  public String getItemType() {
939  return getClass().getName();
940  }
941 
942  @Override
943  public <T> T accept(ContentNodeVisitor<T> visitor) {
944  return visitor.visit(this);
945  }
946 }
Pair< DataResultViewerTable.Score, String > getScorePropertyAndDescription(List< Tag > tags)
final void addTagProperty(Sheet.Set sheetSet, List< Tag > tags)
void fillPropertyMap(Map< String, Object > map, BlackboardArtifact artifact)
static String getStringTime(long epochSeconds, TimeZone tzone)
BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath)
List< ContentTag > getContentTagsByContent(Content content)
static Lookup createLookup(BlackboardArtifact artifact)
Pair< Long, String > getCountPropertyAndDescription(Type attributeType, String attributeValue, String defaultDescription)
static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file)
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
final void addScorePropertyAndDescription(Sheet.Set sheetSet, List< Tag > tags)
static AbstractFile findLinked(BlackboardArtifact artifact)
static CorrelationAttributeInstance getInstanceFromContent(Content content)
void addEmailMsgProperty(Map< String, Object > map, BlackboardAttribute attribute)
final void addCommentProperty(Sheet.Set sheetSet, List< Tag > tags, CorrelationAttributeInstance attribute)
final CorrelationAttributeInstance getCorrelationAttributeInstance()
DataResultViewerTable.HasCommentStatus getCommentProperty(List< Tag > tags, CorrelationAttributeInstance attribute)
final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:477
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:522
static ViewFileInTimelineAction createViewFileAction(AbstractFile file)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.