Autopsy  3.1
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-2014 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 java.util.ArrayList;
22 import java.util.Arrays;
23 import java.util.LinkedHashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.logging.Level;
27 import org.openide.nodes.Children;
28 import org.openide.nodes.Sheet;
29 import org.openide.util.Lookup;
30 import org.openide.util.NbBundle;
31 import org.openide.util.lookup.Lookups;
42 
48 
50  private final Content associated;
51  private List<NodeProperty<? extends Object>> customProperties;
52  static final Logger logger = Logger.getLogger(BlackboardArtifactNode.class.getName());
53  /*
54  * Artifact types which should have the full unique path of the associated
55  * content as a property.
56  */
57  private static final Integer[] SHOW_UNIQUE_PATH = new Integer[] {
61  };
62 
63  // TODO (RC): This is an unattractive alternative to subclassing BlackboardArtifactNode,
64  // cut from the same cloth as the equally unattractive SHOW_UNIQUE_PATH array
65  // above. It should be removed when and if the subclassing is implemented.
66  private static final Integer[] SHOW_FILE_METADATA = new Integer[] {
68  };
69 
77  public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
78  super(Children.LEAF, createLookup(artifact));
79 
80  this.artifact = artifact;
81  //this.associated = getAssociatedContent(artifact);
82  this.associated = this.getLookup().lookup(Content.class);
83  this.setName(Long.toString(artifact.getArtifactID()));
84  this.setDisplayName();
85  this.setIconBaseWithExtension(iconPath);
86  }
87 
95  super(Children.LEAF, createLookup(artifact));
96 
97  this.artifact = artifact;
98  //this.associated = getAssociatedContent(artifact);
99  this.associated = this.getLookup().lookup(Content.class);
100  this.setName(Long.toString(artifact.getArtifactID()));
101  this.setDisplayName();
102  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/" + getIcon(BlackboardArtifact.ARTIFACT_TYPE.fromID(artifact.getArtifactTypeID()))); //NON-NLS
103  }
104 
110  private void setDisplayName() {
111  String displayName = "";
112  if (associated != null)
113  displayName = associated.getName();
114 
115  // If this is a node for a keyword hit on an artifact, we set the
116  // display name to be the artifact type name followed by " Artifact"
117  // e.g. "Messages Artifact".
118  if (artifact != null && artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
119  try {
120  for (BlackboardAttribute attribute : artifact.getAttributes()) {
121  if (attribute.getAttributeTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
122  BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
123  if (associatedArtifact != null) {
124  displayName = associatedArtifact.getDisplayName() + " Artifact"; // NON-NLS
125  }
126  }
127  }
128  }
129  catch (TskCoreException ex) {
130  // Do nothing since the display name will be set to the file name.
131  }
132  }
133  this.setDisplayName(displayName);
134  }
135 
136  @Override
137  protected Sheet createSheet() {
138  Sheet s = super.createSheet();
139  Sheet.Set ss = s.get(Sheet.PROPERTIES);
140  if (ss == null) {
141  ss = Sheet.createPropertiesSet();
142  s.put(ss);
143  }
144  final String NO_DESCR = NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.noDesc.text");
145 
146  Map<String, Object> map = new LinkedHashMap<>();
147  fillPropertyMap(map, artifact);
148 
149  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.name"),
150  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.srcFile.displayName"),
151  NO_DESCR,
152  this.getDisplayName()));
153 
154  for (Map.Entry<String, Object> entry : map.entrySet()) {
155  ss.put(new NodeProperty<>(entry.getKey(),
156  entry.getKey(),
157  NO_DESCR,
158  entry.getValue()));
159  }
160 
161  //append custom node properties
162  if (customProperties != null) {
163  for (NodeProperty<? extends Object> np : customProperties) {
164  ss.put(np);
165  }
166  }
167  final int artifactTypeId = artifact.getArtifactTypeID();
168 
169  // If mismatch, add props for extension and file type
170  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
171  String ext = "";
172  if (associated instanceof AbstractFile) {
173  AbstractFile af = (AbstractFile) associated;
174  ext = af.getNameExtension();
175  }
176  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.name"),
177  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.ext.displayName"),
178  NO_DESCR,
179  ext));
180 
181  try {
182  String actualMimeType = "";
183  ArrayList<BlackboardArtifact> artList = associated.getAllArtifacts();
184  for (BlackboardArtifact art : artList) {
185  List<BlackboardAttribute> atrList = art.getAttributes();
186  for (BlackboardAttribute att : atrList) {
187  if (att.getAttributeTypeID() == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_FILE_TYPE_SIG.getTypeID()) {
188  actualMimeType = att.getValueString();
189  }
190  }
191  }
192  if (actualMimeType.isEmpty()) {
193  logger.log(Level.WARNING, "Could not find expected TSK_FILE_TYPE_SIG attribute."); //NON-NLS
194  } else {
195  ss.put(new NodeProperty<>(
196  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.name"),
197  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.mimeType.displayName"),
198  NO_DESCR,
199  actualMimeType));
200  }
201  } catch (TskCoreException ex) {
202  logger.log(Level.WARNING, "Error while searching for TSK_FILE_TYPE_SIG attribute: ", ex); //NON-NLS
203  }
204  }
205 
206  if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
207  String sourcePath = "";
208  try {
209  sourcePath = associated.getUniquePath();
210  } catch (TskCoreException ex) {
211  logger.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
212  }
213 
214  if (sourcePath.isEmpty() == false) {
215  ss.put(new NodeProperty<>(
216  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.name"),
217  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.filePath.displayName"),
218  NO_DESCR,
219  sourcePath));
220  }
221 
222  if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
223  AbstractFile file = associated instanceof AbstractFile ? (AbstractFile)associated : null;
224  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.name"),
225  NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileModifiedTime.displayName"),
226  "",
227  file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
228  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.name"),
229  NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileChangedTime.displayName"),
230  "",
231  file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
232  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.name"),
233  NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileAccessedTime.displayName"),
234  "",
235  file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
236  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.name"),
237  NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileCreatedTime.displayName"),
238  "",
239  file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
240  ss.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.name"),
241  NbBundle.getMessage(this.getClass(), "ContentTagNode.createSheet.fileSize.displayName"),
242  "",
243  associated.getSize()));
244  }
245  } else {
246  String dataSourceStr = "";
247  try {
248  Content dataSource = associated.getDataSource();
249  if (dataSource != null) {
250  dataSourceStr = dataSource.getName();
251  } else {
252  dataSourceStr = getRootParentName();
253  }
254  } catch (TskCoreException ex) {
255  logger.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
256  }
257 
258  if (dataSourceStr.isEmpty() == false) {
259  ss.put(new NodeProperty<>(
260  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.name"),
261  NbBundle.getMessage(this.getClass(), "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
262  NO_DESCR,
263  dataSourceStr));
264  }
265  }
266 
267  return s;
268  }
269 
270  private String getRootParentName() {
271  String parentName = associated.getName();
272  Content parent = associated;
273  try {
274  while ((parent = parent.getParent()) != null) {
275  parentName = parent.getName();
276  }
277  } catch (TskCoreException ex) {
278  logger.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
279  return "";
280  }
281  return parentName;
282  }
283 
290  public <T> void addNodeProperty(NodeProperty<T> np) {
291  if (null == customProperties) {
292  //lazy create the list
293  customProperties = new ArrayList<>();
294  }
295  customProperties.add(np);
296 
297  }
298 
306  @SuppressWarnings("deprecation") // TODO: Remove this when TSK_TAGGED_ARTIFACT rows are removed in a database upgrade.
307  private void fillPropertyMap(Map<String, Object> map, BlackboardArtifact artifact) {
308  try {
309  for (BlackboardAttribute attribute : artifact.getAttributes()) {
310  final int attributeTypeID = attribute.getAttributeTypeID();
311  //skip some internal attributes that user shouldn't see
312  if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
313  || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
314  || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
315  || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
316  } else if (attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME.getTypeID()
317  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_ACCESSED.getTypeID()
318  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_CREATED.getTypeID()
319  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_MODIFIED.getTypeID()
320  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_RCVD.getTypeID()
321  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_SENT.getTypeID()
322  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_START.getTypeID()
323  || attributeTypeID == ATTRIBUTE_TYPE.TSK_DATETIME_END.getTypeID()) {
324  map.put(attribute.getAttributeTypeDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
325  } else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID() &&
326  attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
327  /* This was added because the RegRipper output would often cause the UI to
328  * get a black line accross it and hang if you hovered over large output
329  * or selected it. This reduces the amount of data in the table.
330  * Could consider doing this for all fields in the UI.
331  */
332  String value = attribute.getDisplayString();
333  if (value.length() > 512)
334  value = value.substring(0, 512);
335  map.put(attribute.getAttributeTypeDisplayName(), value);
336  }
337  else {
338  map.put(attribute.getAttributeTypeDisplayName(), attribute.getDisplayString());
339  }
340  }
341  } catch (TskException ex) {
342  logger.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
343  }
344  }
345 
346  @Override
347  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
348  return v.visit(this);
349  }
350 
357  private static Lookup createLookup(BlackboardArtifact artifact) {
358  List<Object> forLookup = new ArrayList<>();
359  forLookup.add(artifact);
360 
361  // Add the content the artifact is associated with
362  Content content = getAssociatedContent(artifact);
363  if (content != null) {
364  forLookup.add(content);
365  }
366 
367  // if there is a text highlighted version, of the content, add it too
368  // currently happens from keyword search module
369  TextMarkupLookup highlight = getHighlightLookup(artifact, content);
370  if (highlight != null) {
371  forLookup.add(highlight);
372  }
373 
374  return Lookups.fixed(forLookup.toArray(new Object[forLookup.size()]));
375  }
376 
378  try {
379  return artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
380  } catch (TskException ex) {
381  logger.log(Level.WARNING, "Getting file failed", ex); //NON-NLS
382  }
383  throw new IllegalArgumentException(
384  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.getAssocCont.exception.msg"));
385  }
386 
387  private static TextMarkupLookup getHighlightLookup(BlackboardArtifact artifact, Content content) {
388  if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
389  return null;
390  }
391 
392  long objectId = content.getId();
393 
394  Lookup lookup = Lookup.getDefault();
395  TextMarkupLookup highlightFactory = lookup.lookup(TextMarkupLookup.class);
396  try {
397  List<BlackboardAttribute> attributes = artifact.getAttributes();
398  String keyword = null;
399  String regexp = null;
400  for (BlackboardAttribute att : attributes) {
401  final int attributeTypeID = att.getAttributeTypeID();
402  if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
403  keyword = att.getValueString();
404  } else if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) {
405  regexp = att.getValueString();
406  }
407  else if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
408  objectId = att.getValueLong();
409  }
410  }
411  if (keyword != null) {
412  boolean isRegexp = (regexp != null && !regexp.equals(""));
413  String origQuery;
414  if (isRegexp) {
415  origQuery = regexp;
416  } else {
417  origQuery = keyword;
418  }
419  return highlightFactory.createInstance(objectId, keyword, isRegexp, origQuery);
420  }
421  } catch (TskException ex) {
422  logger.log(Level.WARNING, "Failed to retrieve Blackboard Attributes", ex); //NON-NLS
423  }
424  return null;
425  }
426 
427  // @@@ TODO: Merge with ArtifactTypeNode.getIcon()
428  private String getIcon(BlackboardArtifact.ARTIFACT_TYPE type) {
429  switch (type) {
430  case TSK_WEB_BOOKMARK:
431  return "bookmarks.png"; //NON-NLS
432  case TSK_WEB_COOKIE:
433  return "cookies.png"; //NON-NLS
434  case TSK_WEB_HISTORY:
435  return "history.png"; //NON-NLS
436  case TSK_WEB_DOWNLOAD:
437  return "downloads.png"; //NON-NLS
438  case TSK_INSTALLED_PROG:
439  return "programs.png"; //NON-NLS
440  case TSK_RECENT_OBJECT:
441  return "recent_docs.png"; //NON-NLS
442  case TSK_DEVICE_ATTACHED:
443  return "usb_devices.png"; //NON-NLS
444  case TSK_WEB_SEARCH_QUERY:
445  return "searchquery.png"; //NON-NLS
446  case TSK_TAG_FILE:
447  return "blue-tag-icon-16.png"; //NON-NLS
448  case TSK_TAG_ARTIFACT:
449  return "green-tag-icon-16.png"; //NON-NLS
450  case TSK_METADATA_EXIF:
451  return "camera-icon-16.png"; //NON-NLS
452  case TSK_EMAIL_MSG:
453  return "mail-icon-16.png"; //NON-NLS
454  case TSK_CONTACT:
455  return "contact.png"; //NON-NLS
456  case TSK_MESSAGE:
457  return "message.png"; //NON-NLS
458  case TSK_CALLLOG:
459  return "calllog.png"; //NON-NLS
460  case TSK_CALENDAR_ENTRY:
461  return "calendar.png"; //NON-NLS
462  case TSK_SPEED_DIAL_ENTRY:
463  return "speeddialentry.png"; //NON-NLS
464  case TSK_BLUETOOTH_PAIRING:
465  return "bluetooth.png"; //NON-NLS
466  case TSK_GPS_BOOKMARK:
467  return "gpsfav.png"; //NON-NLS
468  case TSK_GPS_LAST_KNOWN_LOCATION:
469  return "gps-lastlocation.png"; //NON-NLS
470  case TSK_GPS_SEARCH:
471  return "gps-search.png"; //NON-NLS
472  case TSK_SERVICE_ACCOUNT:
473  return "account-icon-16.png"; //NON-NLS
474  case TSK_ENCRYPTION_DETECTED:
475  return "encrypted-file.png"; //NON-NLS
476  case TSK_EXT_MISMATCH_DETECTED:
477  return "mismatch-16.png"; //NON-NLS
478  case TSK_OS_INFO:
479  return "computer.png"; //NON-NLS
480  default:
481  return "artifact-icon.png"; //NON-NLS
482  }
483  }
484 
485  @Override
486  public boolean isLeafTypeNode() {
487  return true;
488  }
489 }
void fillPropertyMap(Map< String, Object > map, BlackboardArtifact artifact)
static String getStringTime(long epochSeconds, TimeZone tzone)
BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath)
static Lookup createLookup(BlackboardArtifact artifact)
BlackboardArtifact getBlackboardArtifact(long artifactID)
static Content getAssociatedContent(BlackboardArtifact artifact)
String getIcon(BlackboardArtifact.ARTIFACT_TYPE type)
static TextMarkupLookup getHighlightLookup(BlackboardArtifact artifact, Content content)
List< BlackboardAttribute > getAttributes()
ArrayList< BlackboardArtifact > getAllArtifacts()
TextMarkupLookup createInstance(long objectId, String keywordHitQuery, boolean isRegex, String originalQuery)
static Logger getLogger(String name)
Definition: Logger.java:131

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