Autopsy  4.8.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
AbstractAbstractFileNode.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 java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.util.ArrayList;
24 import java.util.EnumSet;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Set;
28 import java.util.logging.Level;
29 import java.util.stream.Collectors;
30 import org.apache.commons.lang3.StringUtils;
31 import org.openide.nodes.Children;
32 import org.openide.nodes.Sheet;
33 import org.openide.util.NbBundle;
34 import org.openide.util.WeakListeners;
49 import static org.sleuthkit.autopsy.datamodel.Bundle.*;
53 import org.sleuthkit.datamodel.AbstractFile;
54 import org.sleuthkit.datamodel.BlackboardArtifact;
55 import org.sleuthkit.datamodel.Content;
56 import org.sleuthkit.datamodel.ContentTag;
57 import org.sleuthkit.datamodel.TskCoreException;
58 import org.sleuthkit.datamodel.TskData;
59 
65 public abstract class AbstractAbstractFileNode<T extends AbstractFile> extends AbstractContentNode<T> {
66 
67  private static final Logger logger = Logger.getLogger(AbstractAbstractFileNode.class.getName());
68  @NbBundle.Messages("AbstractAbstractFileNode.addFileProperty.desc=no description")
69  private static final String NO_DESCR = AbstractAbstractFileNode_addFileProperty_desc();
70 
71  private static final Set<Case.Events> CASE_EVENTS_OF_INTEREST = EnumSet.of(Case.Events.CURRENT_CASE,
73 
77  AbstractAbstractFileNode(T abstractFile) {
78  super(abstractFile);
79  String ext = abstractFile.getNameExtension();
80  if (StringUtils.isNotBlank(ext)) {
81  ext = "." + ext;
82  // If this is an archive file we will listen for ingest events
83  // that will notify us when new content has been identified.
84  if (FileTypeExtensions.getArchiveExtensions().contains(ext)) {
86  }
87  }
88  // Listen for case events so that we can detect when the case is closed
89  // or when tags are added.
91  }
92 
102  @Override
103  protected void finalize() throws Throwable {
104  super.finalize();
105  removeListeners();
106  }
107 
108  private void removeListeners() {
111  }
112 
113  private final PropertyChangeListener pcl = (PropertyChangeEvent evt) -> {
114  String eventType = evt.getPropertyName();
115 
116  // Is this a content changed event?
117  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
118  if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
119  return;
120  }
121  ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
122  if ((moduleContentEvent.getSource() instanceof Content) == false) {
123  return;
124  }
125  Content newContent = (Content) moduleContentEvent.getSource();
126 
127  // Does the event indicate that content has been added to *this* file?
128  if (getContent().getId() == newContent.getId()) {
129  // If so, refresh our children.
130  try {
131  Children parentsChildren = getParentNode().getChildren();
132  // We only want to refresh our parents children if we are in the
133  // data sources branch of the tree. The parent nodes in other
134  // branches of the tree (e.g. File Types and Deleted Files) do
135  // not need to be refreshed.
136  if (parentsChildren instanceof ContentChildren) {
137  ((ContentChildren) parentsChildren).refreshChildren();
138  parentsChildren.getNodesCount();
139  }
140  } catch (NullPointerException ex) {
141  // Skip
142  }
143  }
144  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
145  if (evt.getNewValue() == null) {
146  // case was closed. Remove listeners so that we don't get called with a stale case handle
147  removeListeners();
148  }
149  } else if (eventType.equals(Case.Events.CONTENT_TAG_ADDED.toString())) {
151  if (event.getAddedTag().getContent().equals(content)) {
152  updateSheet();
153  }
154  } else if (eventType.equals(Case.Events.CONTENT_TAG_DELETED.toString())) {
156  if (event.getDeletedTagInfo().getContentID() == content.getId()) {
157  updateSheet();
158  }
159  } else if (eventType.equals(Case.Events.CR_COMMENT_CHANGED.toString())) {
161  if (event.getContentID() == content.getId()) {
162  updateSheet();
163  }
164  }
165  };
166 
175  private final PropertyChangeListener weakPcl = WeakListeners.propertyChange(pcl, null);
176 
177  private void updateSheet() {
178  this.setSheet(createSheet());
179  }
180 
181  @NbBundle.Messages({"AbstractAbstractFileNode.nameColLbl=Name",
182  "AbstractAbstractFileNode.locationColLbl=Location",
183  "AbstractAbstractFileNode.modifiedTimeColLbl=Modified Time",
184  "AbstractAbstractFileNode.changeTimeColLbl=Change Time",
185  "AbstractAbstractFileNode.accessTimeColLbl=Access Time",
186  "AbstractAbstractFileNode.createdTimeColLbl=Created Time",
187  "AbstractAbstractFileNode.sizeColLbl=Size",
188  "AbstractAbstractFileNode.flagsDirColLbl=Flags(Dir)",
189  "AbstractAbstractFileNode.flagsMetaColLbl=Flags(Meta)",
190  "AbstractAbstractFileNode.modeColLbl=Mode",
191  "AbstractAbstractFileNode.useridColLbl=UserID",
192  "AbstractAbstractFileNode.groupidColLbl=GroupID",
193  "AbstractAbstractFileNode.metaAddrColLbl=Meta Addr.",
194  "AbstractAbstractFileNode.attrAddrColLbl=Attr. Addr.",
195  "AbstractAbstractFileNode.typeDirColLbl=Type(Dir)",
196  "AbstractAbstractFileNode.typeMetaColLbl=Type(Meta)",
197  "AbstractAbstractFileNode.knownColLbl=Known",
198  "AbstractAbstractFileNode.md5HashColLbl=MD5 Hash",
199  "AbstractAbstractFileNode.objectId=Object ID",
200  "AbstractAbstractFileNode.mimeType=MIME Type",
201  "AbstractAbstractFileNode.extensionColLbl=Extension"})
203 
204  NAME(AbstractAbstractFileNode_nameColLbl()),
205  LOCATION(AbstractAbstractFileNode_locationColLbl()),
206  MOD_TIME(AbstractAbstractFileNode_modifiedTimeColLbl()),
207  CHANGED_TIME(AbstractAbstractFileNode_changeTimeColLbl()),
208  ACCESS_TIME(AbstractAbstractFileNode_accessTimeColLbl()),
209  CREATED_TIME(AbstractAbstractFileNode_createdTimeColLbl()),
210  SIZE(AbstractAbstractFileNode_sizeColLbl()),
211  FLAGS_DIR(AbstractAbstractFileNode_flagsDirColLbl()),
212  FLAGS_META(AbstractAbstractFileNode_flagsMetaColLbl()),
213  MODE(AbstractAbstractFileNode_modeColLbl()),
214  USER_ID(AbstractAbstractFileNode_useridColLbl()),
215  GROUP_ID(AbstractAbstractFileNode_groupidColLbl()),
216  META_ADDR(AbstractAbstractFileNode_metaAddrColLbl()),
217  ATTR_ADDR(AbstractAbstractFileNode_attrAddrColLbl()),
218  TYPE_DIR(AbstractAbstractFileNode_typeDirColLbl()),
219  TYPE_META(AbstractAbstractFileNode_typeMetaColLbl()),
220  KNOWN(AbstractAbstractFileNode_knownColLbl()),
221  MD5HASH(AbstractAbstractFileNode_md5HashColLbl()),
222  ObjectID(AbstractAbstractFileNode_objectId()),
223  MIMETYPE(AbstractAbstractFileNode_mimeType()),
224  EXTENSION(AbstractAbstractFileNode_extensionColLbl());
225 
226  final private String displayString;
227 
228  private AbstractFilePropertyType(String displayString) {
229  this.displayString = displayString;
230  }
231 
232  @Override
233  public String toString() {
234  return displayString;
235  }
236  }
237 
245  static public void fillPropertyMap(Map<String, Object> map, AbstractFile content) {
246  map.put(NAME.toString(), getContentDisplayName(content));
247  map.put(LOCATION.toString(), getContentPath(content));
248  map.put(MOD_TIME.toString(), ContentUtils.getStringTime(content.getMtime(), content));
249  map.put(CHANGED_TIME.toString(), ContentUtils.getStringTime(content.getCtime(), content));
250  map.put(ACCESS_TIME.toString(), ContentUtils.getStringTime(content.getAtime(), content));
251  map.put(CREATED_TIME.toString(), ContentUtils.getStringTime(content.getCrtime(), content));
252  map.put(SIZE.toString(), content.getSize());
253  map.put(FLAGS_DIR.toString(), content.getDirFlagAsString());
254  map.put(FLAGS_META.toString(), content.getMetaFlagsAsString());
255  map.put(MODE.toString(), content.getModesAsString());
256  map.put(USER_ID.toString(), content.getUid());
257  map.put(GROUP_ID.toString(), content.getGid());
258  map.put(META_ADDR.toString(), content.getMetaAddr());
259  map.put(ATTR_ADDR.toString(), content.getAttrType().getValue() + "-" + content.getAttributeId());
260  map.put(TYPE_DIR.toString(), content.getDirType().getLabel());
261  map.put(TYPE_META.toString(), content.getMetaType().toString());
262  map.put(KNOWN.toString(), content.getKnown().getName());
263  map.put(MD5HASH.toString(), StringUtils.defaultString(content.getMd5Hash()));
264  map.put(ObjectID.toString(), content.getId());
265  map.put(MIMETYPE.toString(), StringUtils.defaultString(content.getMIMEType()));
266  map.put(EXTENSION.toString(), content.getNameExtension());
267  }
268 
274  protected final List<ContentTag> getContentTagsFromDatabase() {
275  List<ContentTag> tags = new ArrayList<>();
276  try {
278  } catch (TskCoreException | NoCurrentCaseException ex) {
279  logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
280  }
281  return tags;
282  }
283 
285  CorrelationAttributeInstance correlationAttribute = null;
286  if (EamDbUtil.useCentralRepo()) {
287  correlationAttribute = EamArtifactUtil.getInstanceFromContent(content);
288  }
289  return correlationAttribute;
290  }
291 
302  @NbBundle.Messages({"AbstractAbstractFileNode.createSheet.comment.name=C",
303  "AbstractAbstractFileNode.createSheet.comment.displayName=C"})
304  protected final void addCommentProperty(Sheet.Set sheetSet, List<ContentTag> tags, CorrelationAttributeInstance attribute) {
305 
307 
308  for (ContentTag tag : tags) {
309  if (!StringUtils.isBlank(tag.getComment())) {
310  //if the tag is null or empty or contains just white space it will indicate there is not a comment
311  status = HasCommentStatus.TAG_COMMENT;
312  break;
313  }
314  }
315  if (attribute != null && !StringUtils.isBlank(attribute.getComment())) {
316  if (status == HasCommentStatus.TAG_COMMENT) {
318  } else {
319  status = HasCommentStatus.CR_COMMENT;
320  }
321  }
322  sheetSet.put(new NodeProperty<>(AbstractAbstractFileNode_createSheet_comment_name(), AbstractAbstractFileNode_createSheet_comment_displayName(), NO_DESCR,
323  status));
324  }
325 
334  @NbBundle.Messages({"AbstractAbstractFileNode.createSheet.score.name=S",
335  "AbstractAbstractFileNode.createSheet.score.displayName=S",
336  "AbstractAbstractFileNode.createSheet.notableFile.description=File recognized as notable.",
337  "AbstractAbstractFileNode.createSheet.interestingResult.description=File has interesting result associated with it.",
338  "AbstractAbstractFileNode.createSheet.taggedFile.description=File has been tagged.",
339  "AbstractAbstractFileNode.createSheet.notableTaggedFile.description=File tagged with notable tag.",
340  "AbstractAbstractFileNode.createSheet.noScore.description=No score"})
341  protected final void addScoreProperty(Sheet.Set sheetSet, List<ContentTag> tags) {
342  Score score = Score.NO_SCORE;
343  String description = Bundle.AbstractAbstractFileNode_createSheet_noScore_description();
344  if (content.getKnown() == TskData.FileKnown.BAD) {
345  score = Score.NOTABLE_SCORE;
346  description = Bundle.AbstractAbstractFileNode_createSheet_notableFile_description();
347  }
348  try {
349  if (score == Score.NO_SCORE && !content.getArtifacts(BlackboardArtifact.ARTIFACT_TYPE.TSK_INTERESTING_FILE_HIT).isEmpty()) {
350  score = Score.INTERESTING_SCORE;
351  description = Bundle.AbstractAbstractFileNode_createSheet_interestingResult_description();
352  }
353  } catch (TskCoreException ex) {
354  logger.log(Level.WARNING, "Error getting artifacts for file: " + content.getName(), ex);
355  }
356  if (tags.size() > 0 && (score == Score.NO_SCORE || score == Score.INTERESTING_SCORE)) {
357  score = Score.INTERESTING_SCORE;
358  description = Bundle.AbstractAbstractFileNode_createSheet_taggedFile_description();
359  for (ContentTag tag : tags) {
360  if (tag.getName().getKnownStatus() == TskData.FileKnown.BAD) {
361  score = Score.NOTABLE_SCORE;
362  description = Bundle.AbstractAbstractFileNode_createSheet_notableTaggedFile_description();
363  break;
364  }
365  }
366  }
367  sheetSet.put(new NodeProperty<>(Bundle.AbstractAbstractFileNode_createSheet_score_name(), Bundle.AbstractAbstractFileNode_createSheet_score_displayName(), description, score));
368  }
369 
370  @NbBundle.Messages({"AbstractAbstractFileNode.createSheet.count.name=O",
371  "AbstractAbstractFileNode.createSheet.count.displayName=O",
372  "AbstractAbstractFileNode.createSheet.count.noCentralRepo.description=Central repository was not enabled when this column was populated",
373  "AbstractAbstractFileNode.createSheet.count.hashLookupNotRun.description=Hash lookup had not been run on this file when the column was populated",
374  "# {0} - occuranceCount",
375  "AbstractAbstractFileNode.createSheet.count.description=There were {0} datasource(s) found with occurances of the correlation value"})
376  protected final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute) {
377  Long count = -1L; //The column renderer will not display negative values, negative value used when count unavailble to preserve sorting
378  String description = Bundle.AbstractAbstractFileNode_createSheet_count_noCentralRepo_description();
379  try {
380  //don't perform the query if there is no correlation value
381  if (attribute != null && StringUtils.isNotBlank(attribute.getCorrelationValue())) {
383  description = Bundle.AbstractAbstractFileNode_createSheet_count_description(count);
384  } else if (attribute != null) {
385  description = Bundle.AbstractAbstractFileNode_createSheet_count_hashLookupNotRun_description();
386  }
387  } catch (EamDbException ex) {
388  logger.log(Level.WARNING, "Error getting count of datasources with correlation attribute", ex);
390  logger.log(Level.WARNING, "Unable to normalize data to get count of datasources with correlation attribute", ex);
391  }
392 
393  sheetSet.put(
394  new NodeProperty<>(Bundle.AbstractAbstractFileNode_createSheet_count_name(), Bundle.AbstractAbstractFileNode_createSheet_count_displayName(), description, count));
395  }
396 
405  @NbBundle.Messages("AbstractAbstractFileNode.tagsProperty.displayName=Tags")
406  @Deprecated
407  protected void addTagProperty(Sheet.Set sheetSet) {
408  List<ContentTag> tags = new ArrayList<>();
409  try {
411  } catch (TskCoreException | NoCurrentCaseException ex) {
412  logger.log(Level.SEVERE, "Failed to get tags for content " + content.getName(), ex);
413  }
414  sheetSet.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
415  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
416  .distinct()
417  .collect(Collectors.joining(", "))));
418  }
419 
429  @Deprecated
430  protected final void addTagProperty(Sheet.Set sheetSet, List<ContentTag> tags) {
431  sheetSet.put(new NodeProperty<>("Tags", AbstractAbstractFileNode_tagsProperty_displayName(),
432  NO_DESCR, tags.stream().map(t -> t.getName().getDisplayName())
433  .distinct()
434  .collect(Collectors.joining(", "))));
435  }
436 
437  private static String getContentPath(AbstractFile file) {
438  try {
439  return file.getUniquePath();
440  } catch (TskCoreException ex) {
441  logger.log(Level.SEVERE, "Except while calling Content.getUniquePath() on " + file, ex); //NON-NLS
442  return ""; //NON-NLS
443  }
444  }
445 
446  static String getContentDisplayName(AbstractFile file) {
447  String name = file.getName();
448  switch (name) {
449  case "..":
450  return DirectoryNode.DOTDOTDIR;
451 
452  case ".":
453  return DirectoryNode.DOTDIR;
454  default:
455  return name;
456  }
457  }
458 
468  @Deprecated
469  protected static String getHashSetHitsCsvList(AbstractFile file) {
470  try {
471  return StringUtils.join(file.getHashSetNames(), ", ");
472  } catch (TskCoreException tskCoreException) {
473  logger.log(Level.WARNING, "Error getting hashset hits: ", tskCoreException); //NON-NLS
474  return "";
475  }
476  }
477 }
final void addScoreProperty(Sheet.Set sheetSet, List< ContentTag > tags)
void removeIngestModuleEventListener(final PropertyChangeListener listener)
static String getStringTime(long epochSeconds, TimeZone tzone)
static synchronized IngestManager getInstance()
List< ContentTag > getContentTagsByContent(Content content)
static void fillPropertyMap(Map< String, Object > map, AbstractFile content)
Long getCountUniqueCaseDataSourceTuplesHavingTypeValue(CorrelationAttributeInstance.Type aType, String value)
static CorrelationAttributeInstance getInstanceFromContent(Content content)
final void addTagProperty(Sheet.Set sheetSet, List< ContentTag > tags)
final void addCountProperty(Sheet.Set sheetSet, CorrelationAttributeInstance attribute)
final void addCommentProperty(Sheet.Set sheetSet, List< ContentTag > tags, CorrelationAttributeInstance attribute)
void addIngestModuleEventListener(final PropertyChangeListener listener)
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

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.