Autopsy  4.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-2016 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.text.MessageFormat;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.LinkedHashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.logging.Level;
28 import javax.swing.Action;
29 import org.apache.commons.lang3.StringUtils;
30 import org.openide.nodes.Children;
31 import org.openide.nodes.Sheet;
32 import org.openide.util.Lookup;
33 import org.openide.util.NbBundle;
34 import org.openide.util.lookup.Lookups;
40 import org.sleuthkit.datamodel.AbstractFile;
41 import org.sleuthkit.datamodel.BlackboardArtifact;
42 import org.sleuthkit.datamodel.BlackboardArtifact.ARTIFACT_TYPE;
43 import org.sleuthkit.datamodel.BlackboardAttribute;
44 import org.sleuthkit.datamodel.BlackboardAttribute.ATTRIBUTE_TYPE;
45 import org.sleuthkit.datamodel.Content;
46 import org.sleuthkit.datamodel.TskCoreException;
47 
53 
54  private final BlackboardArtifact artifact;
55  private final Content associated;
56  private List<NodeProperty<? extends Object>> customProperties;
57  private static final Logger LOGGER = Logger.getLogger(BlackboardArtifactNode.class.getName());
58  /*
59  * Artifact types which should have the full unique path of the associated
60  * content as a property.
61  */
62  private static final Integer[] SHOW_UNIQUE_PATH = new Integer[]{
63  BlackboardArtifact.ARTIFACT_TYPE.TSK_HASHSET_HIT.getTypeID(),
64  BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID(),
65  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
66 
67  // TODO (RC): This is an unattractive alternative to subclassing BlackboardArtifactNode,
68  // cut from the same cloth as the equally unattractive SHOW_UNIQUE_PATH array
69  // above. It should be removed when and if the subclassing is implemented.
70  private static final Integer[] SHOW_FILE_METADATA = new Integer[]{
71  BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT.getTypeID(),};
72 
80  public BlackboardArtifactNode(BlackboardArtifact artifact, String iconPath) {
81  super(Children.LEAF, createLookup(artifact));
82 
83  this.artifact = artifact;
84  //this.associated = getAssociatedContent(artifact);
85  this.associated = this.getLookup().lookup(Content.class);
86  this.setName(Long.toString(artifact.getArtifactID()));
87  this.setDisplayName();
88  this.setIconBaseWithExtension(iconPath);
89  }
90 
97  public BlackboardArtifactNode(BlackboardArtifact artifact) {
98  super(Children.LEAF, createLookup(artifact));
99 
100  this.artifact = artifact;
101  //this.associated = getAssociatedContent(artifact);
102  this.associated = this.getLookup().lookup(Content.class);
103  this.setName(Long.toString(artifact.getArtifactID()));
104  this.setDisplayName();
105  this.setIconBaseWithExtension(ExtractedContent.getIconFilePath(artifact.getArtifactTypeID())); //NON-NLS
106  }
107 
108  @Override
109  @NbBundle.Messages({
110  "BlackboardArtifactNode.getAction.errorTitle=Error getting actions",
111  "BlackboardArtifactNode.getAction.resultErrorMessage=There was a problem getting actions for the selected result."
112  + " The 'View Result in Timeline' action will not be available.",
113  "BlackboardArtifactNode.getAction.linkedFileMessage=There was a problem getting actions for the selected result. "
114  + " The 'View File in Timeline' action will not be available."})
115  public Action[] getActions(boolean context) {
116  List<Action> actionsList = new ArrayList<>();
117  actionsList.addAll(Arrays.asList(super.getActions(context)));
118 
119  //if this artifact has a time stamp add the action to view it in the timeline
120  try {
122  actionsList.add(new ViewArtifactInTimelineAction(artifact));
123  }
124  } catch (TskCoreException ex) {
125  LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting arttribute(s) from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
126  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_resultErrorMessage());
127  }
128 
129  // if the artifact links to another file, add an action to go to that file
130  try {
131  AbstractFile c = findLinked(artifact);
132  if (c != null) {
134  }
135  } catch (TskCoreException ex) {
136  LOGGER.log(Level.SEVERE, MessageFormat.format("Error getting linked file from blackboard artifact{0}.", artifact.getArtifactID()), ex); //NON-NLS
137  MessageNotifyUtil.Notify.error(Bundle.BlackboardArtifactNode_getAction_errorTitle(), Bundle.BlackboardArtifactNode_getAction_linkedFileMessage());
138  }
139 
140  //if this artifact has associated content, add the action to view the content in the timeline
141  AbstractFile file = getLookup().lookup(AbstractFile.class);
142  if (null != file) {
144  }
145 
146  return actionsList.toArray(new Action[actionsList.size()]);
147  }
148 
154  private void setDisplayName() {
155  String displayName = ""; //NON-NLS
156  if (associated != null) {
157  displayName = associated.getName();
158  }
159 
160  // If this is a node for a keyword hit on an artifact, we set the
161  // display name to be the artifact type name followed by " Artifact"
162  // e.g. "Messages Artifact".
163  if (artifact != null && artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
164  try {
165  for (BlackboardAttribute attribute : artifact.getAttributes()) {
166  if (attribute.getAttributeType().getTypeID() == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
167  BlackboardArtifact associatedArtifact = Case.getCurrentCase().getSleuthkitCase().getBlackboardArtifact(attribute.getValueLong());
168  if (associatedArtifact != null) {
169  displayName = associatedArtifact.getDisplayName() + " Artifact";
170  }
171  }
172  }
173  } catch (TskCoreException ex) {
174  // Do nothing since the display name will be set to the file name.
175  }
176  }
177  this.setDisplayName(displayName);
178  }
179 
180  @Override
181  protected Sheet createSheet() {
182  Sheet s = super.createSheet();
183  Sheet.Set ss = s.get(Sheet.PROPERTIES);
184  if (ss == null) {
185  ss = Sheet.createPropertiesSet();
186  s.put(ss);
187  }
188  final String NO_DESCR = NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.noDesc.text");
189 
190  Map<String, Object> map = new LinkedHashMap<>();
191  fillPropertyMap(map, artifact);
192 
193  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.name"),
194  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.srcFile.displayName"),
195  NO_DESCR,
196  this.getDisplayName()));
197 
198  for (Map.Entry<String, Object> entry : map.entrySet()) {
199  ss.put(new NodeProperty<>(entry.getKey(),
200  entry.getKey(),
201  NO_DESCR,
202  entry.getValue()));
203  }
204 
205  //append custom node properties
206  if (customProperties != null) {
207  for (NodeProperty<? extends Object> np : customProperties) {
208  ss.put(np);
209  }
210  }
211  final int artifactTypeId = artifact.getArtifactTypeID();
212 
213  // If mismatch, add props for extension and file type
214  if (artifactTypeId == BlackboardArtifact.ARTIFACT_TYPE.TSK_EXT_MISMATCH_DETECTED.getTypeID()) {
215  String ext = ""; //NON-NLS
216  String actualMimeType = ""; //NON-NLS
217  if (associated instanceof AbstractFile) {
218  AbstractFile af = (AbstractFile) associated;
219  ext = af.getNameExtension();
220  actualMimeType = af.getMIMEType();
221  if (actualMimeType == null) {
222  actualMimeType = ""; //NON-NLS
223  }
224  }
225  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.name"),
226  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.ext.displayName"),
227  NO_DESCR,
228  ext));
229  ss.put(new NodeProperty<>(
230  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.name"),
231  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.mimeType.displayName"),
232  NO_DESCR,
233  actualMimeType));
234  }
235 
236  if (Arrays.asList(SHOW_UNIQUE_PATH).contains(artifactTypeId)) {
237  String sourcePath = ""; //NON-NLS
238  try {
239  sourcePath = associated.getUniquePath();
240  } catch (TskCoreException ex) {
241  LOGGER.log(Level.WARNING, "Failed to get unique path from: {0}", associated.getName()); //NON-NLS
242  }
243 
244  if (sourcePath.isEmpty() == false) {
245  ss.put(new NodeProperty<>(
246  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.name"),
247  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.filePath.displayName"),
248  NO_DESCR,
249  sourcePath));
250  }
251 
252  if (Arrays.asList(SHOW_FILE_METADATA).contains(artifactTypeId)) {
253  AbstractFile file = associated instanceof AbstractFile ? (AbstractFile) associated : null;
254  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.name"),
255  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileModifiedTime.displayName"),
256  "",
257  file != null ? ContentUtils.getStringTime(file.getMtime(), file) : ""));
258  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.name"),
259  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileChangedTime.displayName"),
260  "",
261  file != null ? ContentUtils.getStringTime(file.getCtime(), file) : ""));
262  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.name"),
263  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileAccessedTime.displayName"),
264  "",
265  file != null ? ContentUtils.getStringTime(file.getAtime(), file) : ""));
266  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.name"),
267  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileCreatedTime.displayName"),
268  "",
269  file != null ? ContentUtils.getStringTime(file.getCrtime(), file) : ""));
270  ss.put(new NodeProperty<>(NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.name"),
271  NbBundle.getMessage(BlackboardArtifactNode.class, "ContentTagNode.createSheet.fileSize.displayName"),
272  "",
273  associated.getSize()));
274  }
275  } else {
276  String dataSourceStr = "";
277  try {
278  Content dataSource = associated.getDataSource();
279  if (dataSource != null) {
280  dataSourceStr = dataSource.getName();
281  } else {
282  dataSourceStr = getRootParentName();
283  }
284  } catch (TskCoreException ex) {
285  LOGGER.log(Level.WARNING, "Failed to get image name from {0}", associated.getName()); //NON-NLS
286  }
287 
288  if (dataSourceStr.isEmpty() == false) {
289  ss.put(new NodeProperty<>(
290  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.name"),
291  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.createSheet.dataSrc.displayName"),
292  NO_DESCR,
293  dataSourceStr));
294  }
295  }
296 
297  return s;
298  }
299 
300  private String getRootParentName() {
301  String parentName = associated.getName();
302  Content parent = associated;
303  try {
304  while ((parent = parent.getParent()) != null) {
305  parentName = parent.getName();
306  }
307  } catch (TskCoreException ex) {
308  LOGGER.log(Level.WARNING, "Failed to get parent name from {0}", associated.getName()); //NON-NLS
309  return "";
310  }
311  return parentName;
312  }
313 
321  if (null == customProperties) {
322  //lazy create the list
323  customProperties = new ArrayList<>();
324  }
325  customProperties.add(np);
326  }
327 
335  @SuppressWarnings("deprecation")
336  private void fillPropertyMap(Map<String, Object> map, BlackboardArtifact artifact) {
337  try {
338  for (BlackboardAttribute attribute : artifact.getAttributes()) {
339  final int attributeTypeID = attribute.getAttributeType().getTypeID();
340  //skip some internal attributes that user shouldn't see
341  if (attributeTypeID == ATTRIBUTE_TYPE.TSK_PATH_ID.getTypeID()
342  || attributeTypeID == ATTRIBUTE_TYPE.TSK_TAGGED_ARTIFACT.getTypeID()
343  || attributeTypeID == ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()
344  || attributeTypeID == ATTRIBUTE_TYPE.TSK_SET_NAME.getTypeID()) {
345  } else if (attribute.getAttributeType().getValueType() == BlackboardAttribute.TSK_BLACKBOARD_ATTRIBUTE_VALUE_TYPE.DATETIME) {
346  map.put(attribute.getAttributeType().getDisplayName(), ContentUtils.getStringTime(attribute.getValueLong(), associated));
347  } else if (artifact.getArtifactTypeID() == ARTIFACT_TYPE.TSK_TOOL_OUTPUT.getTypeID()
348  && attributeTypeID == ATTRIBUTE_TYPE.TSK_TEXT.getTypeID()) {
349  /*
350  * This was added because the RegRipper output would often
351  * cause the UI to get a black line accross it and hang if
352  * you hovered over large output or selected it. This
353  * reduces the amount of data in the table. Could consider
354  * doing this for all fields in the UI.
355  */
356  String value = attribute.getDisplayString();
357  if (value.length() > 512) {
358  value = value.substring(0, 512);
359  }
360  map.put(attribute.getAttributeType().getDisplayName(), value);
361  } else {
362  map.put(attribute.getAttributeType().getDisplayName(), attribute.getDisplayString());
363  }
364  }
365  } catch (TskCoreException ex) {
366  LOGGER.log(Level.SEVERE, "Getting attributes failed", ex); //NON-NLS
367  }
368  }
369 
370  @Override
371  public <T> T accept(DisplayableItemNodeVisitor<T> v) {
372  return v.visit(this);
373  }
374 
382  private static Lookup createLookup(BlackboardArtifact artifact) {
383  List<Object> forLookup = new ArrayList<>();
384  forLookup.add(artifact);
385 
386  // Add the content the artifact is associated with
387  Content content = getAssociatedContent(artifact);
388  if (content != null) {
389  forLookup.add(content);
390  }
391 
392  // if there is a text highlighted version, of the content, add it too
393  // currently happens from keyword search module
394  TextMarkupLookup highlight = getHighlightLookup(artifact, content);
395  if (highlight != null) {
396  forLookup.add(highlight);
397  }
398 
399  return Lookups.fixed(forLookup.toArray(new Object[forLookup.size()]));
400  }
401 
402  private static Content getAssociatedContent(BlackboardArtifact artifact) {
403  try {
404  return artifact.getSleuthkitCase().getContentById(artifact.getObjectID());
405  } catch (TskCoreException ex) {
406  LOGGER.log(Level.WARNING, "Getting file failed", ex); //NON-NLS
407  }
408  throw new IllegalArgumentException(
409  NbBundle.getMessage(BlackboardArtifactNode.class, "BlackboardArtifactNode.getAssocCont.exception.msg"));
410  }
411 
412  private static TextMarkupLookup getHighlightLookup(BlackboardArtifact artifact, Content content) {
413  if (artifact.getArtifactTypeID() != BlackboardArtifact.ARTIFACT_TYPE.TSK_KEYWORD_HIT.getTypeID()) {
414  return null;
415  }
416 
417  long objectId = content.getId();
418 
419  Lookup lookup = Lookup.getDefault();
420  TextMarkupLookup highlightFactory = lookup.lookup(TextMarkupLookup.class);
421  try {
422  List<BlackboardAttribute> attributes = artifact.getAttributes();
423  String keyword = null;
424  String regexp = null;
425  for (BlackboardAttribute att : attributes) {
426  final int attributeTypeID = att.getAttributeType().getTypeID();
427  if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD.getTypeID()) {
428  keyword = att.getValueString();
429  } else if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_KEYWORD_REGEXP.getTypeID()) {
430  regexp = att.getValueString();
431  } else if (attributeTypeID == BlackboardAttribute.ATTRIBUTE_TYPE.TSK_ASSOCIATED_ARTIFACT.getTypeID()) {
432  objectId = att.getValueLong();
433  }
434  }
435  if (keyword != null) {
436  boolean isRegexp = StringUtils.isNotBlank(regexp);
437  String origQuery = isRegexp ? regexp : keyword;
438  return highlightFactory.createInstance(objectId, keyword, isRegexp, origQuery);
439  }
440  } catch (TskCoreException ex) {
441  LOGGER.log(Level.WARNING, "Failed to retrieve Blackboard Attributes", ex); //NON-NLS
442  }
443  return null;
444  }
445 
446  @Override
447  public boolean isLeafTypeNode() {
448  return true;
449  }
450 
451  /*
452  * TODO (AUT-1849): Correct or remove peristent column reordering code
453  *
454  * Added to support this feature.
455  */
456 // @Override
457 // public String getItemType() {
458 // return "BlackboardArtifact"; //NON-NLS
459 // }
460 }
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)
TextMarkupLookup createInstance(long objectId, String keyword, boolean isRegex, String originalQuery)
static Content getAssociatedContent(BlackboardArtifact artifact)
static ViewFileInTimelineAction createViewSourceFileAction(AbstractFile file)
static TextMarkupLookup getHighlightLookup(BlackboardArtifact artifact, Content content)
static void error(String title, String message)
synchronized static Logger getLogger(String name)
Definition: Logger.java:161
static ViewFileInTimelineAction createViewFileAction(AbstractFile file)

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