Autopsy  4.15.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileTypesByExtension.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 java.beans.PropertyChangeEvent;
22 import java.beans.PropertyChangeListener;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.EnumSet;
26 import java.util.List;
27 import java.util.Observable;
28 import java.util.Observer;
29 import java.util.Set;
30 import java.util.logging.Level;
31 import java.util.stream.Collectors;
32 import org.apache.commons.lang.StringUtils;
33 import org.openide.nodes.ChildFactory;
34 import org.openide.nodes.Children;
35 import org.openide.nodes.Node;
36 import org.openide.nodes.Sheet;
37 import org.openide.util.NbBundle;
38 import org.openide.util.NbBundle.Messages;
39 import org.openide.util.lookup.Lookups;
47 import org.sleuthkit.datamodel.AbstractFile;
48 import org.sleuthkit.datamodel.SleuthkitCase;
49 import org.sleuthkit.datamodel.TskCoreException;
50 import org.sleuthkit.datamodel.TskData;
51 
55 public final class FileTypesByExtension implements AutopsyVisitableItem {
56 
57  private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
60  private final SleuthkitCase skCase;
61  private final FileTypes typesRoot;
62 
63  public FileTypesByExtension(FileTypes typesRoot) {
64  this.skCase = typesRoot.getSleuthkitCase();
65  this.typesRoot = typesRoot;
66  }
67 
68  public SleuthkitCase getSleuthkitCase() {
69  return this.skCase;
70  }
71 
72  @Override
73  public <T> T accept(AutopsyItemVisitor<T> visitor) {
74  return visitor.visit(this);
75  }
76 
77  long filteringDataSourceObjId() {
78  return typesRoot.filteringDataSourceObjId();
79  }
80 
85  private class FileTypesByExtObservable extends Observable implements RefreshThrottler.Refresher {
86 
87  private final PropertyChangeListener pcl;
88  private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
94  private final RefreshThrottler refreshThrottler = new RefreshThrottler(this);
95 
97  super();
99  this.pcl = (PropertyChangeEvent evt) -> {
100  String eventType = evt.getPropertyName();
101  if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
102  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
103  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
104 
111  try {
113  typesRoot.updateShowCounts();
114  update();
115  } catch (NoCurrentCaseException notUsed) {
119  }
120  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
121  // case was closed. Remove listeners so that we don't get called with a stale case handle
122  if (evt.getNewValue() == null) {
123  removeListeners();
124  }
125  }
126  };
127 
129  refreshThrottler.registerForIngestModuleEvents();
131  }
132 
133  private void removeListeners() {
134  deleteObservers();
136  refreshThrottler.unregisterEventListener();
138  }
139 
140  private void update() {
141  setChanged();
142  notifyObservers();
143  }
144 
145  @Override
146  public void refresh() {
147  typesRoot.updateShowCounts();
148  update();
149  }
150 
151  @Override
152  public boolean isRefreshRequired(PropertyChangeEvent evt) {
153  String eventType = evt.getPropertyName();
154  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
155 
162  try {
168  if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
169  return false;
170  }
171  ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
172  if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) {
173  return false;
174  }
175  AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource();
176  if (!abstractFile.getNameExtension().isEmpty()) {
177  return true;
178  }
179  } catch (NoCurrentCaseException ex) {
183  return false;
184  }
185  }
186  return false;
187  }
188  }
189 
190  private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
191 
195  class FileTypesByExtNode extends DisplayableItemNode {
196 
197  private final FileTypesByExtension.RootFilter filter;
198 
205  FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) {
206  this(skCase, filter, null);
207  }
208 
216  private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
217 
218  super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true),
219  Lookups.singleton(filter == null ? FNAME : filter.getDisplayName()));
220  this.filter = filter;
221 
222  // root node of tree
223  if (filter == null) {
224  super.setName(FNAME);
225  super.setDisplayName(FNAME);
226  } // sub-node in file tree (i.e. documents, exec, etc.)
227  else {
228  super.setName(filter.getDisplayName());
229  super.setDisplayName(filter.getDisplayName());
230  }
231  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
232  }
233 
234  @Override
235  public boolean isLeafTypeNode() {
236  return false;
237  }
238 
239  @Override
240  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
241  return visitor.visit(this);
242  }
243 
244  @Override
245  protected Sheet createSheet() {
246  Sheet sheet = super.createSheet();
247  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
248  if (sheetSet == null) {
249  sheetSet = Sheet.createPropertiesSet();
250  sheet.put(sheetSet);
251  }
252  if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) {
253  String extensions = "";
254  for (String ext : filter.getFilter()) {
255  extensions += "'" + ext + "', ";
256  }
257  extensions = extensions.substring(0, extensions.lastIndexOf(','));
258  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"), extensions));
259  } else {
260  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.name"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.name.desc"), getDisplayName()));
261  }
262  return sheet;
263  }
264 
265  @Override
266  public String getItemType() {
271  if (filter == null) {
272  return getClass().getName();
273  }
275  return getClass().getName() + filter.getName();
276  }
277  return getClass().getName();
278  }
279 
280  }
281 
282  private class FileTypesByExtNodeChildren extends ChildFactory<FileTypesByExtension.SearchFilterInterface> {
283 
284  private final SleuthkitCase skCase;
287 
296  super();
297  this.skCase = skCase;
298  this.filter = filter;
299  if (o == null) {
300  this.notifier = new FileTypesByExtObservable();
301  } else {
302  this.notifier = o;
303  }
304  }
305 
306  @Override
307  protected boolean createKeys(List<FileTypesByExtension.SearchFilterInterface> list) {
308  // root node
309  if (filter == null) {
310  list.addAll(Arrays.asList(FileTypesByExtension.RootFilter.values()));
311  } // document and executable has another level of nodes
313  list.addAll(Arrays.asList(FileTypesByExtension.DocumentFilter.values()));
315  list.addAll(Arrays.asList(FileTypesByExtension.ExecutableFilter.values()));
316  }
317  return true;
318  }
319 
320  @Override
322  // make new nodes for the sub-nodes
323  if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
324  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER, notifier);
325  } else if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
326  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
327  } else {
328  return new FileExtensionNode(key, skCase, notifier);
329  }
330  }
331  }
332 
337  final class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
338 
339  private final FileTypesByExtension.SearchFilterInterface filter;
340 
348  FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
349  super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o, filter.getDisplayName()), true),
350  Lookups.singleton(filter.getDisplayName()));
351  this.filter = filter;
352  super.setName(filter.getDisplayName());
353  updateDisplayName();
354  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
355 
356  o.addObserver(this);
357  }
358 
359  @Override
360  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
361  return visitor.visit(this);
362  }
363 
364  @Override
365  protected Sheet createSheet() {
366  Sheet sheet = super.createSheet();
367  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
368  if (sheetSet == null) {
369  sheetSet = Sheet.createPropertiesSet();
370  sheet.put(sheetSet);
371  }
372  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"),
373  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"),
374  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"),
375  filter.getDisplayName()));
376 
377  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"),
378  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"),
379  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"),
380  String.join(", ", filter.getFilter())));
381  return sheet;
382  }
383 
384  @Override
385  public boolean isLeafTypeNode() {
386  return true;
387  }
388 
394  @Override
395  public String getItemType() {
396  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
397  }
398 
399  @Override
400  String getDisplayNameBase() {
401  return filter.getDisplayName();
402  }
403 
404  @Override
405  long calculateChildCount() throws TskCoreException {
406  return skCase.countFilesWhere(createQuery(filter));
407  }
408  }
409 
411  if (filter.getFilter().isEmpty()) {
412  // We should never be given a search filter without extensions
413  // but if we are it is clearly a programming error so we throw
414  // an IllegalArgumentException.
415  throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
416  }
417 
418  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
420  ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
421  : " ")
422  + (filteringDataSourceObjId() > 0
423  ? " AND data_source_obj_id = " + filteringDataSourceObjId()
424  : " ")
425  + " AND (extension IN (" + filter.getFilter().stream()
426  .map(String::toLowerCase)
427  .map(s -> "'" + StringUtils.substringAfter(s, ".") + "'")
428  .collect(Collectors.joining(", ")) + "))";
429  }
430 
434  private class FileExtensionNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
435 
436  private final SleuthkitCase skCase;
438  private final Observable notifier;
439 
448  private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
449  super(nodeName, new ViewsKnownAndSlackFilter<>());
450  this.filter = filter;
451  this.skCase = skCase;
452  notifier = o;
453  }
454 
455  @Override
456  protected void onAdd() {
457  if (notifier != null) {
458  notifier.addObserver(this);
459  }
460  }
461 
462  @Override
463  protected void onRemove() {
464  if (notifier != null) {
465  notifier.deleteObserver(this);
466  }
467  }
468 
469  @Override
470  public void update(Observable o, Object arg) {
471  refresh(false);
472  }
473 
474  @Override
475  protected Node createNodeForKey(FileTypesKey key) {
476  return key.accept(new FileTypes.FileNodeCreationVisitor());
477  }
478 
479  @Override
480  protected List<FileTypesKey> makeKeys() {
481  try {
482  return skCase.findAllFilesWhere(createQuery(filter))
483  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList());
484  } catch (TskCoreException ex) {
485  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
486  }
487  return Collections.emptyList();
488  }
489  }
490 
491  // root node filters
492  @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
493  public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
494 
495  TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
496  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskImgFilter.text"),
498  TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", //NON-NLS
499  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskVideoFilter.text"),
501  TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", //NON-NLS
502  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskAudioFilter.text"),
504  TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
505  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
507  TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS
508  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"),
510  TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS
511  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
512  Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
513  TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS
514  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
516 
517  private final int id;
518  private final String name;
519  private final String displayName;
520  private final List<String> filter;
521 
522  private RootFilter(int id, String name, String displayName, List<String> filter) {
523  this.id = id;
524  this.name = name;
525  this.displayName = displayName;
526  this.filter = filter;
527  }
528 
529  @Override
530  public <T> T accept(AutopsyItemVisitor<T> visitor) {
531  return visitor.visit(this);
532  }
533 
534  @Override
535  public String getName() {
536  return this.name;
537  }
538 
539  @Override
540  public int getId() {
541  return this.id;
542  }
543 
544  @Override
545  public String getDisplayName() {
546  return this.displayName;
547  }
548 
549  @Override
550  public List<String> getFilter() {
551  return Collections.unmodifiableList(this.filter);
552  }
553  }
554 
555  // document sub-node filters
556  public static enum DocumentFilter implements AutopsyVisitableItem, SearchFilterInterface {
557 
558  AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS
559  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"),
560  Arrays.asList(".htm", ".html")), //NON-NLS
561  AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS
562  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"),
563  Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS
564  AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS
565  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autoDocPdfFilter.text"),
566  Arrays.asList(".pdf")), //NON-NLS
567  AUT_DOC_TXT(3, "AUT_DOC_TXT", //NON-NLS
568  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocTxtFilter.text"),
569  Arrays.asList(".txt")), //NON-NLS
570  AUT_DOC_RTF(4, "AUT_DOC_RTF", //NON-NLS
571  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
572  Arrays.asList(".rtf")); //NON-NLS
573 
574  private final int id;
575  private final String name;
576  private final String displayName;
577  private final List<String> filter;
578 
579  private DocumentFilter(int id, String name, String displayName, List<String> filter) {
580  this.id = id;
581  this.name = name;
582  this.displayName = displayName;
583  this.filter = filter;
584  }
585 
586  @Override
587  public <T> T accept(AutopsyItemVisitor<T> visitor) {
588  return visitor.visit(this);
589  }
590 
591  @Override
592  public String getName() {
593  return this.name;
594  }
595 
596  @Override
597  public int getId() {
598  return this.id;
599  }
600 
601  @Override
602  public String getDisplayName() {
603  return this.displayName;
604  }
605 
606  @Override
607  public List<String> getFilter() {
608  return Collections.unmodifiableList(this.filter);
609  }
610  }
611 
612  // executable sub-node filters
613  public static enum ExecutableFilter implements AutopsyVisitableItem, SearchFilterInterface {
614 
615  ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")), //NON-NLS
616  ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")), //NON-NLS
617  ExecutableFilter_BAT(2, "ExecutableFilter_BAT", ".bat", Arrays.asList(".bat")), //NON-NLS
618  ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
619  ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
620 
621  private final int id;
622  private final String name;
623  private final String displayName;
624  private final List<String> filter;
625 
626  private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
627  this.id = id;
628  this.name = name;
629  this.displayName = displayName;
630  this.filter = filter;
631  }
632 
633  @Override
634  public <T> T accept(AutopsyItemVisitor<T> visitor) {
635  return visitor.visit(this);
636  }
637 
638  @Override
639  public String getName() {
640  return this.name;
641  }
642 
643  @Override
644  public int getId() {
645  return this.id;
646  }
647 
648  @Override
649  public String getDisplayName() {
650  return this.displayName;
651  }
652 
653  @Override
654  public List<String> getFilter() {
655  return Collections.unmodifiableList(this.filter);
656  }
657  }
658 
659  interface SearchFilterInterface {
660 
661  public String getName();
662 
663  public int getId();
664 
665  public String getDisplayName();
666 
667  public List<String> getFilter();
668 
669  }
670 }
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
static synchronized IngestManager getInstance()
static final Set< IngestManager.IngestModuleEvent > INGEST_MODULE_EVENTS_OF_INTEREST
void removeIngestJobEventListener(final PropertyChangeListener listener)
String createQuery(FileTypesByExtension.SearchFilterInterface filter)
void addIngestJobEventListener(final PropertyChangeListener listener)
FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName)
boolean createKeys(List< FileTypesByExtension.SearchFilterInterface > list)
FileTypesByExtNodeChildren(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o)
RootFilter(int id, String name, String displayName, List< String > filter)
DocumentFilter(int id, String name, String displayName, List< String > filter)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:491
ExecutableFilter(int id, String name, String displayName, List< String > filter)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:536

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