Autopsy  4.8.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-2018 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.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;
31 import java.util.Map;
32 import java.util.MissingResourceException;
33 import java.util.Set;
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;
62 import static org.sleuthkit.autopsy.datamodel.DisplayableItemNode.findLinked;
67 import org.sleuthkit.datamodel.AbstractFile;
68 import org.sleuthkit.datamodel.BlackboardArtifact;
69 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
70 import org.sleuthkit.datamodel.BlackboardAttribute;
71 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
72 import org.sleuthkit.datamodel.Content;
73 import org.sleuthkit.datamodel.Tag;
74 import org.sleuthkit.datamodel.TskCoreException;
75 import org.sleuthkit.datamodel.TskData;
76 
81 public class BlackboardArtifactNode extends AbstractContentNode<BlackboardArtifact> {
82 
83  private static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
90 
91  private static Cache<Long, Content> contentCache = CacheBuilder.newBuilder()
92  .expireAfterWrite(1, TimeUnit.MINUTES).
93  build();
94 
95  private final BlackboardArtifact artifact;
96  private Content associated = null;
97 
98  private List<NodeProperty<? extends Object>> customProperties;
99 
100  private final static String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text");
101 
102 
103  /*
104  * Artifact types which should have the full unique path of the associated
105  * content as a property.
106  */
107  private static final Integer[] SHOW_UNIQUE_PATH = new Integer[]{
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(),};
112 
113  // TODO (RC): This is an unattractive alternative to subclassing BlackboardArtifactNode,
114  // cut from the same cloth as the equally unattractive SHOW_UNIQUE_PATH array
115  // above. It should be removed when and if the subclassing is implemented.
116  private static final Integer[] SHOW_FILE_METADATA = new Integer[]{
117  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
118 
119  private final PropertyChangeListener pcl = new PropertyChangeListener() {
120  @Override
121  public void propertyChange(PropertyChangeEvent evt) {
122  String eventType = evt.getPropertyName();
123  if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_ADDED.toString())) {
125  if (event.getAddedTag().getArtifact().equals(artifact)) {
126  updateSheet();
127  }
128  } else if (eventType.equals(Case.Events.BLACKBOARD_ARTIFACT_TAG_DELETED.toString())) {
130  if (event.getDeletedTagInfo().getArtifactID() == artifact.getArtifactID()) {
131  updateSheet();
132  }
133  } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
135  if (event.getAddedTag().getContent().equals(associated)) {
136  updateSheet();
137  }
138  } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
140  if (event.getDeletedTagInfo().getContentID() == associated.getId()) {
141  updateSheet();
142  }
143  } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
145  if (event.getContentID() == associated.getId()) {
146  updateSheet();
147  }
148  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
149  if (evt.getNewValue() == null) {
150  // case was closed. Remove listeners so that we don't get called with a stale case handle
151  removeListeners();
152  contentCache.invalidateAll();
153  }
154  }
155  }
156  };
157 
166  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
167 
176  public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
177  super(artifact, createLookup(artifact));
178 
179  this.artifact = artifact;
180 
181  // Look for associated Content i.e. the source file for the artifact
182  for (Content lookupContent : this.getLookup().lookupAll(Content.class)) {
183  if ((lookupContent != null) && (!(lookupContent instanceof BlackboardArtifact))) {
184  this.associated = lookupContent;
185  break;
186  }
187  }
188 
189  this.setName(Long.toString(artifact.getArtifactID()));
190  this.setDisplayName();
191  this.setIconBaseWithExtension(iconPath);
193  }
194 
201  public BlackboardArtifactNode(BlackboardArtifact artifact) {
202  this(artifact, ExtractedContent.getIconFilePath(artifact.getArtifactTypeID()));
203  }
204 
214  @Override
215  protected void finalize() throws Throwable {
216  super.finalize();
217  removeListeners();
218  }
219 
220  private void removeListeners() {
222  }
223 
224  public BlackboardArtifact getArtifact() {
225  return this.artifact;
226  }
227 
228  @Override
229  @NbBundle.Messages({
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."})
235  public Action[] getActions(boolean context) {
236  List<Action> actionsList = new ArrayList<>();
237  actionsList.addAll(Arrays.asList(super.getActions(context)));
238  AbstractFile file = getLookup().lookup(AbstractFile.class);
239 
240  //if this artifact has a time stamp add the action to view it in the timeline
241  try {
243  actionsList.add(new ViewArtifactInTimelineAction(artifact));
244  }
245  } catch (TskCoreException ex) {
246  logger.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
247  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
248  }
249 
250  // if the artifact links to another file, add an action to go to that file
251  try {
252  AbstractFile c = findLinked(artifact);
253  if (c != null) {
255  }
256  } catch (TskCoreException ex) {
257  logger.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
258  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
259  }
260 
261  //if the artifact has associated content, add the action to view the content in the timeline
262  if (null != file) {
264  }
265 
266  return actionsList.toArray(new Action[actionsList.size()]);
267  }
268 
269  @NbBundle.Messages({"# {0} - artifactDisplayName", "BlackboardArtifactNode.displayName.artifact={0} Artifact"})
275  private void setDisplayName() {
276  String displayName = ""; //NON-NLS
277 
278  // If this is a node for a keyword hit on an artifact, we set the
279  // display name to be the artifact type name followed by " Artifact"
280  // e.g. "Messages Artifact".
281  if (artifact != null
282  && (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()
283  || artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID())) {
284  try {
285  for (BlackboardAttribute attribute : artifact.getAttributes()) {
286  if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
287  BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
288  if (associatedArtifact != null) {
289  if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
290  artifact.getDisplayName();
291  } else {
292  displayName = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.displayName.artifact", associatedArtifact.getDisplayName());
293  }
294  }
295  }
296  }
297  } catch (TskCoreException | NoCurrentCaseException ex) {
298  // Do nothing since the display name will be set to the file name.
299  }
300  }
301 
302  if (displayName.isEmpty() && artifact != null) {
303  displayName = artifact.getName();
304  }
305 
306  this.setDisplayName(displayName);
307 
308  }
309 
315  public String getSourceName() {
316 
317  String srcName = "";
318  if (associated != null) {
319  srcName = associated.getName();
320  }
321  return srcName;
322  }
323 
324  @NbBundle.Messages({
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"})
336 
337  @Override
338  protected Sheet createSheet() {
339  Sheet sheet = super.createSheet();
340  List<Tag> tags = getAllTagsFromDatabase();
341 
342  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
343  if (sheetSet == null) {
344  sheetSet = Sheet.createPropertiesSet();
345  sheet.put(sheetSet);
346  }
347 
348  Map<String, Object> map = new LinkedHashMap<>();
349  fillPropertyMap(map, artifact);
350 
351  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"),
352  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
353  NO_DESCR,
354  this.getSourceName()));
355 
356  addScoreProperty(sheetSet, tags);
357 
358  CorrelationAttributeInstance correlationAttribute = null;
360  correlationAttribute = getCorrelationAttributeInstance();
361  }
362  addCommentProperty(sheetSet, tags, correlationAttribute);
363 
365  addCountProperty(sheetSet, correlationAttribute);
366  }
367  if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT.getTypeID()) {
368  try {
369  BlackboardAttribute attribute = artifact.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT));
370  if (attribute != null) {
371  BlackboardArtifact associatedArtifact = Case.getCurrentCaseThrows().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
372  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.name"),
373  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactType.displayName"),
374  NO_DESCR,
375  associatedArtifact.getDisplayName() + " " + NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.artifact.displayName")));
376  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.name"),
377  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.artifactDetails.displayName"),
378  NO_DESCR,
379  associatedArtifact.getShortDescription()));
380  }
381  } catch (TskCoreException | NoCurrentCaseException ex) {
382  // Do nothing since the display name will be set to the file name.
383  }
384  }
385 
386  for (Map.Entry<String, Object> entry : map.entrySet()) {
387  sheetSet.put(new NodeProperty<>(entry.getKey(),
388  entry.getKey(),
389  NO_DESCR,
390  entry.getValue()));
391  }
392 
393  //append custom node properties
394  if (customProperties != null) {
395  for (NodeProperty<? extends Object> np : customProperties) {
396  sheetSet.put(np);
397  }
398  }
399 
400  final int artifactTypeId = artifact.getArtifactTypeID();
401 
402  // If mismatch, add props for extension and file type
403  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
404  String ext = ""; //NON-NLS
405  String actualMimeType = ""; //NON-NLS
406  if (associated instanceof AbstractFile) {
407  AbstractFile af = (AbstractFile) associated;
408  ext = af.getNameExtension();
409  actualMimeType = af.getMIMEType();
410  if (actualMimeType == null) {
411  actualMimeType = ""; //NON-NLS
412  }
413  }
414  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
415  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
416  NO_DESCR,
417  ext));
418  sheetSet.put(new NodeProperty<>(
419  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"),
420  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"),
421  NO_DESCR,
422  actualMimeType));
423  }
424 
425  if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
426  String sourcePath = ""; //NON-NLS
427  try {
428  sourcePath = associated.getUniquePath();
429  } catch (TskCoreException ex) {
430  logger.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
431  }
432 
433  if (sourcePath.isEmpty() == false) {
434  sheetSet.put(new NodeProperty<>(
435  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"),
436  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"),
437  NO_DESCR,
438  sourcePath));
439  }
440 
441  if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
442  AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
443  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
444  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
445  "",
446  file == null ? "" : ContentUtils.getStringTime(file.getMtime(), file)));
447  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
448  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
449  "",
450  file == null ? "" : ContentUtils.getStringTime(file.getCtime(), file)));
451  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
452  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
453  "",
454  file == null ? "" : ContentUtils.getStringTime(file.getAtime(), file)));
455  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
456  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
457  "",
458  file == null ? "" : ContentUtils.getStringTime(file.getCrtime(), file)));
459  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
460  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
461  "",
462  associated.getSize()));
463  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_artifactMD5_name(),
464  Bundle.BlackboardArtifactNode_createSheet_artifactMD5_displayName(),
465  "",
466  file == null ? "" : StringUtils.defaultString(file.getMd5Hash())));
467  }
468  } else {
469  String dataSourceStr = "";
470  try {
471  Content dataSource = associated.getDataSource();
472  if (dataSource != null) {
473  dataSourceStr = dataSource.getName();
474  } else {
475  dataSourceStr = getRootParentName();
476  }
477  } catch (TskCoreException ex) {
478  logger.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
479  }
480 
481  if (dataSourceStr.isEmpty() == false) {
482  sheetSet.put(new NodeProperty<>(
483  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"),
484  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
485  NO_DESCR,
486  dataSourceStr));
487  }
488  }
489 
490  // If EXIF, add props for file size and path
491  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_METADATA_EXIF.getTypeID()) {
492 
493  long size = 0;
494  String path = ""; //NON-NLS
495  if (associated instanceof AbstractFile) {
496  AbstractFile af = (AbstractFile) associated;
497  size = af.getSize();
498  try {
499  path = af.getUniquePath();
500  } catch (TskCoreException ex) {
501  path = af.getParentPath();
502  }
503  }
504  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.name"),
505  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.fileSize.displayName"),
506  NO_DESCR,
507  size));
508  sheetSet.put(new NodeProperty<>(
509  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.name"),
510  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.path.displayName"),
511  NO_DESCR,
512  path));
513  }
514 
515  return sheet;
516  }
517 
525  protected final List<Tag> getAllTagsFromDatabase() {
526  List<Tag> tags = new ArrayList<>();
527  try {
530  } catch (TskCoreException | NoCurrentCaseException ex) {
531  logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
532  }
533  return tags;
534  }
535 
543  @NbBundle.Messages({
544  "BlackboardArtifactNode.createSheet.tags.displayName=Tags"})
545  @Deprecated
546  protected void addTagProperty(Sheet.Set sheetSet) throws MissingResourceException {
547  // add properties for tags
548  List<Tag> tags = new ArrayList<>();
549  try {
552  } catch (TskCoreException | NoCurrentCaseException ex) {
553  logger.log(Level.SEVERE, "Failed to get tags for artifact " + artifact.getDisplayName(), ex);
554  }
555  sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
556  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
557  }
558 
568  @Deprecated
569  protected final void addTagProperty(Sheet.Set sheetSet, List<Tag> tags) {
570  sheetSet.put(new NodeProperty<>("Tags", Bundle.BlackboardArtifactNode_createSheet_tags_displayName(),
571  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName()).collect(Collectors.joining(", "))));
572  }
573 
575  CorrelationAttributeInstance correlationAttribute = null;
576  if (EamDbUtil.useCentralRepo()) {
577  correlationAttribute = EamArtifactUtil.getInstanceFromContent(associated);
578  }
579  return correlationAttribute;
580  }
581 
593  @NbBundle.Messages({"BlackboardArtifactNode.createSheet.comment.name=C",
594  "BlackboardArtifactNode.createSheet.comment.displayName=C"})
595  protected final void addCommentProperty(Sheet.Set sheetSet, List<Tag> tags, CorrelationAttributeInstance attribute) {
597  for (Tag tag : tags) {
598  if (!StringUtils.isBlank(tag.getComment())) {
599  //if the tag is null or empty or contains just white space it will indicate there is not a comment
600  status = HasCommentStatus.TAG_COMMENT;
601  break;
602  }
603  }
604  //currently checks for a comment on the associated file in the central repo not the artifact itself
605  //what we want the column property to reflect should be revisted when we have added a way to comment
606  //on the artifact itself
607  if (attribute != null && !StringUtils.isBlank(attribute.getComment())) {
608  if (status == HasCommentStatus.TAG_COMMENT) {
610  } else {
611  status = HasCommentStatus.CR_COMMENT;
612  }
613  }
614  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_comment_name(), Bundle.BlackboardArtifactNode_createSheet_comment_displayName(), NO_DESCR,
615  status));
616  }
617 
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"})
633  protected final void addScoreProperty(Sheet.Set sheetSet, List<Tag> tags) {
634  Score score = Score.NO_SCORE;
635  String description = Bundle.BlackboardArtifactNode_createSheet_noScore_description();
636  if (associated instanceof AbstractFile) {
637  if (((AbstractFile) associated).getKnown() == TskData.FileKnown.BAD) {
638  score = Score.NOTABLE_SCORE;
639  description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
640  }
641  }
642  //if the artifact being viewed is a hashhit check if the hashset is notable
643  if ((score == Score.NO_SCORE || score == Score.INTERESTING_SCORE) && content.getArtifactTypeID() == ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID()) {
644  try {
645  BlackboardAttribute attr = content.getAttribute(new BlackboardAttribute.Type(ATTRIBUTE_TYPE.TSK_SET_NAME));
647  for (HashDbManager.HashDb hashDb : notableHashsets) {
648  if (hashDb.getHashSetName().equals(attr.getValueString())) {
649  score = Score.NOTABLE_SCORE;
650  description = Bundle.BlackboardArtifactNode_createSheet_notableFile_description();
651  break;
652  }
653  }
654  } catch (TskCoreException ex) {
655  //unable to get the attribute so we can not update the status based on the attribute
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);
657  }
658  }
659  try {
660  if (score == Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_ARTIFACT_HIT).isEmpty()) {
661  score = Score.INTERESTING_SCORE;
662  description = Bundle.BlackboardArtifactNode_createSheet_interestingResult_description();
663  }
664  } catch (TskCoreException ex) {
665  logger.log(Level.WARNING, "Error getting artifacts for artifact: " + content.getName(), ex);
666  }
667  if (tags.size() > 0 && (score == Score.NO_SCORE || score == Score.INTERESTING_SCORE)) {
668  score = Score.INTERESTING_SCORE;
669  description = Bundle.BlackboardArtifactNode_createSheet_taggedItem_description();
670  for (Tag tag : tags) {
671  if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
672  score = Score.NOTABLE_SCORE;
673  description = Bundle.BlackboardArtifactNode_createSheet_notableTaggedItem_description();
674  break;
675  }
676  }
677  }
678  sheetSet.put(new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_score_name(), Bundle.BlackboardArtifactNode_createSheet_score_displayName(), description, score));
679  }
680 
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"})
687 
688  protected final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute) {
689  Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
690  String description = Bundle.BlackboardArtifactNode_createSheet_count_noCentralRepo_description();
691  try {
692  //don't perform the query if there is no correlation value
693  if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
695  description = Bundle.BlackboardArtifactNode_createSheet_count_description(count);
696  } else if (attribute != null) {
697  description = Bundle.BlackboardArtifactNode_createSheet_count_hashLookupNotRun_description();
698  }
699  } catch (EamDbException ex) {
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);
703  }
704  sheetSet.put(
705  new NodeProperty<>(Bundle.BlackboardArtifactNode_createSheet_count_name(), Bundle.BlackboardArtifactNode_createSheet_count_displayName(), description, count));
706  }
707 
708  private void updateSheet() {
709  this.setSheet(createSheet());
710  }
711 
712  private String getRootParentName() {
713  String parentName = associated.getName();
714  Content parent = associated;
715  try {
716  while ((parent = parent.getParent()) != null) {
717  parentName = parent.getName();
718  }
719  } catch (TskCoreException ex) {
720  logger.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
721  return "";
722  }
723  return parentName;
724  }
725 
733  if (null == customProperties) {
734  //lazy create the list
735  customProperties = new ArrayList<>();
736  }
737  customProperties.add(np);
738  }
739 
747  @SuppressWarnings("deprecation")
748  private void fillPropertyMap(Map<String, Object> map, BlackboardArtifact artifact) {
749  try {
750  for (BlackboardAttribute attribute : artifact.getAttributes()) {
751  final int attributeTypeID = attribute.getAttributeType().getTypeID();
752  //skip some internal attributes that user shouldn't see
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()) {
759  addEmailMsgProperty(map, attribute);
760  } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
761  map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
762  } else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
763  && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
764  /*
765  * This was added because the RegRipper output would often
766  * cause the UI to get a black line accross it and hang if
767  * you hovered over large output or selected it. This
768  * reduces the amount of data in the table. Could consider
769  * doing this for all fields in the UI.
770  */
771  String value = attribute.getDisplayString();
772  if (value.length() > 512) {
773  value = value.substring(0, 512);
774  }
775  map.put(attribute.getAttributeType().getDisplayName(), value);
776  } else {
777  map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
778  }
779  }
780  } catch (TskCoreException ex) {
781  logger.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
782  }
783  }
784 
792  private void addEmailMsgProperty(Map<String, Object> map, BlackboardAttribute attribute) {
793 
794  final int attributeTypeID = attribute.getAttributeType().getTypeID();
795 
796  // Skip certain Email msg attributes
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()) {
803 
804  // do nothing
805  } else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_EMAIL_CONTENT_PLAIN.getTypeID()) {
806 
807  String value = attribute.getDisplayString();
808  if (value.length() > 160) {
809  value = value.substring(0, 160) + "...";
810  }
811  map.put(attribute.getAttributeType().getDisplayName(), value);
812  } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
813  map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
814  } else {
815  map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
816  }
817 
818  }
819 
820  @Override
821  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
822  return visitor.visit(this);
823  }
824 
833  private static Lookup createLookup(BlackboardArtifact artifact) {
834  // Add the content the artifact is associated with
835  final long objectID = artifact.getObjectID();
836  try {
837  Content content = contentCache.get(objectID, () -> artifact.getSleuthkitCase().getContentById(objectID));
838  if (content == null) {
839  return Lookups.fixed(artifact);
840  } else {
841  return Lookups.fixed(artifact, content);
842  }
843  } catch (ExecutionException ex) {
844  logger.log(Level.WARNING, "Getting associated content for artifact failed", ex); //NON-NLS
845  return Lookups.fixed(artifact);
846  }
847  }
848 
849  @Override
850  public boolean isLeafTypeNode() {
851  return true;
852  }
853 
854  @Override
855  public String getItemType() {
856  return getClass().getName();
857  }
858 
859  @Override
860  public <T> T accept(ContentNodeVisitor<T> visitor) {
861  return visitor.visit(this);
862  }
863 }
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)
final void addScoreProperty(Sheet.Set sheetSet, List< Tag > tags)
static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file)
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
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()
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:428
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:473
static ViewFileInTimelineAction createViewFileAction(AbstractFile file)
List< BlackboardArtifactTag > getBlackboardArtifactTagsByArtifact(BlackboardArtifact artifact)

Copyright © 2012-2018 Basis Technology. Generated on: Thu Oct 4 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.