Autopsy  4.19.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.Exceptions;
38 import org.openide.util.NbBundle;
39 import org.openide.util.NbBundle.Messages;
40 import org.openide.util.lookup.Lookups;
48 import org.sleuthkit.datamodel.AbstractFile;
49 import org.sleuthkit.datamodel.SleuthkitCase;
50 import org.sleuthkit.datamodel.TskCoreException;
51 import org.sleuthkit.datamodel.TskData;
53 
57 public final class FileTypesByExtension implements AutopsyVisitableItem {
58 
59  private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
62  private final FileTypes typesRoot;
63 
64  public FileTypesByExtension(FileTypes typesRoot) {
65  this.typesRoot = typesRoot;
66  }
67 
68  public SleuthkitCase getSleuthkitCase() {
69  try {
71  } catch (NoCurrentCaseException ex) {
72  return null;
73  }
74  }
75 
76  @Override
77  public <T> T accept(AutopsyItemVisitor<T> visitor) {
78  return visitor.visit(this);
79  }
80 
81  long filteringDataSourceObjId() {
82  return typesRoot.filteringDataSourceObjId();
83  }
84 
89  private class FileTypesByExtObservable extends Observable implements RefreshThrottler.Refresher {
90 
91  private final PropertyChangeListener pcl;
92  private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
99 
101  super();
103  this.pcl = (PropertyChangeEvent evt) -> {
104  String eventType = evt.getPropertyName();
105  if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
106  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
107  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
108 
115  try {
117  typesRoot.updateShowCounts();
118  update();
119  } catch (NoCurrentCaseException notUsed) {
123  }
124  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
125  // case was closed. Remove listeners so that we don't get called with a stale case handle
126  if (evt.getNewValue() == null) {
127  removeListeners();
128  }
129  }
130  };
131 
133  refreshThrottler.registerForIngestModuleEvents();
135  }
136 
137  private void removeListeners() {
138  deleteObservers();
140  refreshThrottler.unregisterEventListener();
142  }
143 
144  private void update() {
145  setChanged();
146  notifyObservers();
147  }
148 
149  @Override
150  public void refresh() {
151  typesRoot.updateShowCounts();
152  update();
153  }
154 
155  @Override
156  public boolean isRefreshRequired(PropertyChangeEvent evt) {
157  String eventType = evt.getPropertyName();
158  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())) {
159 
166  try {
172  if ((evt.getOldValue() instanceof ModuleContentEvent) == false) {
173  return false;
174  }
175  ModuleContentEvent moduleContentEvent = (ModuleContentEvent) evt.getOldValue();
176  if ((moduleContentEvent.getSource() instanceof AbstractFile) == false) {
177  return false;
178  }
179  AbstractFile abstractFile = (AbstractFile) moduleContentEvent.getSource();
180  if (!abstractFile.getNameExtension().isEmpty()) {
181  return true;
182  }
183  } catch (NoCurrentCaseException ex) {
187  return false;
188  }
189  }
190  return false;
191  }
192  }
193 
194  private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
195 
199  class FileTypesByExtNode extends DisplayableItemNode {
200 
201  private final FileTypesByExtension.RootFilter filter;
202 
209  FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) {
210  this(skCase, filter, null);
211  }
212 
220  private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
221 
222  super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true),
223  Lookups.singleton(filter == null ? FNAME : filter.getDisplayName()));
224  this.filter = filter;
225 
226  // root node of tree
227  if (filter == null) {
228  super.setName(FNAME);
229  super.setDisplayName(FNAME);
230  } // sub-node in file tree (i.e. documents, exec, etc.)
231  else {
232  super.setName(filter.getDisplayName());
233  super.setDisplayName(filter.getDisplayName());
234  }
235  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
236  }
237 
238  @Override
239  public boolean isLeafTypeNode() {
240  return false;
241  }
242 
243  @Override
244  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
245  return visitor.visit(this);
246  }
247 
248  @Override
249  protected Sheet createSheet() {
250  Sheet sheet = super.createSheet();
251  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
252  if (sheetSet == null) {
253  sheetSet = Sheet.createPropertiesSet();
254  sheet.put(sheetSet);
255  }
256  if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) {
257  String extensions = "";
258  for (String ext : filter.getFilter()) {
259  extensions += "'" + ext + "', ";
260  }
261  extensions = extensions.substring(0, extensions.lastIndexOf(','));
262  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));
263  } else {
264  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()));
265  }
266  return sheet;
267  }
268 
269  @Override
270  public String getItemType() {
275  if (filter == null) {
276  return getClass().getName();
277  }
279  return getClass().getName() + filter.getName();
280  }
281  return getClass().getName();
282  }
283 
284  }
285 
286  private class FileTypesByExtNodeChildren extends ChildFactory<FileTypesByExtension.SearchFilterInterface> {
287 
288  private final SleuthkitCase skCase;
291 
300  super();
301  this.skCase = skCase;
302  this.filter = filter;
303  if (o == null) {
304  this.notifier = new FileTypesByExtObservable();
305  } else {
306  this.notifier = o;
307  }
308  }
309 
310  @Override
311  protected boolean createKeys(List<FileTypesByExtension.SearchFilterInterface> list) {
312  // root node
313  if (filter == null) {
314  list.addAll(Arrays.asList(FileTypesByExtension.RootFilter.values()));
315  } // document and executable has another level of nodes
317  list.addAll(Arrays.asList(FileTypesByExtension.DocumentFilter.values()));
319  list.addAll(Arrays.asList(FileTypesByExtension.ExecutableFilter.values()));
320  }
321  return true;
322  }
323 
324  @Override
326  // make new nodes for the sub-nodes
327  if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
328  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER, notifier);
329  } else if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
330  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
331  } else {
332  return new FileExtensionNode(key, skCase, notifier);
333  }
334  }
335  }
336 
341  final class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
342 
343  private final FileTypesByExtension.SearchFilterInterface filter;
344 
352  FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
353  super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o, filter.getDisplayName()), true),
354  Lookups.singleton(filter.getDisplayName()));
355  this.filter = filter;
356  super.setName(filter.getDisplayName());
357  updateDisplayName();
358  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
359 
360  o.addObserver(this);
361  }
362 
363  @Override
364  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
365  return visitor.visit(this);
366  }
367 
368  @Override
369  protected Sheet createSheet() {
370  Sheet sheet = super.createSheet();
371  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
372  if (sheetSet == null) {
373  sheetSet = Sheet.createPropertiesSet();
374  sheet.put(sheetSet);
375  }
376  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"),
377  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"),
378  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"),
379  filter.getDisplayName()));
380 
381  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"),
382  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"),
383  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"),
384  String.join(", ", filter.getFilter())));
385  return sheet;
386  }
387 
388  @Override
389  public boolean isLeafTypeNode() {
390  return true;
391  }
392 
398  @Override
399  public String getItemType() {
400  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
401  }
402 
403  @Override
404  String getDisplayNameBase() {
405  return filter.getDisplayName();
406  }
407 
408  @Override
409  long calculateChildCount() throws TskCoreException {
410  try {
411  return Case.getCurrentCaseThrows().getSleuthkitCase().countFilesWhere(createQuery(filter));
412  } catch (NoCurrentCaseException ex) {
413  throw new TskCoreException("No open case.", ex);
414  }
415  }
416  }
417 
419  if (filter.getFilter().isEmpty()) {
420  // We should never be given a search filter without extensions
421  // but if we are it is clearly a programming error so we throw
422  // an IllegalArgumentException.
423  throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
424  }
425 
426  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
428  ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
429  : " ")
430  + (filteringDataSourceObjId() > 0
431  ? " AND data_source_obj_id = " + filteringDataSourceObjId()
432  : " ")
433  + " AND (extension IN (" + filter.getFilter().stream()
434  .map(String::toLowerCase)
435  .map(s -> "'" + StringUtils.substringAfter(s, ".") + "'")
436  .collect(Collectors.joining(", ")) + "))";
437  }
438 
442  private class FileExtensionNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
443 
444  private final SleuthkitCase skCase;
446  private final Observable notifier;
447 
456  private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
457  super(nodeName, new ViewsKnownAndSlackFilter<>());
458  this.filter = filter;
459  this.skCase = skCase;
460  notifier = o;
461  }
462 
463  @Override
464  protected void onAdd() {
465  if (notifier != null) {
466  notifier.addObserver(this);
467  }
468  }
469 
470  @Override
471  protected void onRemove() {
472  if (notifier != null) {
473  notifier.deleteObserver(this);
474  }
475  }
476 
477  @Override
478  public void update(Observable o, Object arg) {
479  refresh(false);
480  }
481 
482  @Override
483  protected Node createNodeForKey(FileTypesKey key) {
484  return key.accept(new FileTypes.FileNodeCreationVisitor());
485  }
486 
487  @Override
488  protected List<FileTypesKey> makeKeys() {
489  try {
490  return skCase.findAllFilesWhere(createQuery(filter))
491  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList());
492  } catch (TskCoreException ex) {
493  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
494  }
495  return Collections.emptyList();
496  }
497  }
498 
499  // root node filters
500  @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
501  public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
502 
503  TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
504  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskImgFilter.text"),
506  TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", //NON-NLS
507  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskVideoFilter.text"),
509  TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", //NON-NLS
510  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskAudioFilter.text"),
512  TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
513  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
515  TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS
516  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"),
518  TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS
519  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
520  Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
521  TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS
522  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
524 
525  private final int id;
526  private final String name;
527  private final String displayName;
528  private final List<String> filter;
529 
530  private RootFilter(int id, String name, String displayName, List<String> filter) {
531  this.id = id;
532  this.name = name;
533  this.displayName = displayName;
534  this.filter = filter;
535  }
536 
537  @Override
538  public <T> T accept(AutopsyItemVisitor<T> visitor) {
539  return visitor.visit(this);
540  }
541 
542  @Override
543  public String getName() {
544  return this.name;
545  }
546 
547  @Override
548  public int getId() {
549  return this.id;
550  }
551 
552  @Override
553  public String getDisplayName() {
554  return this.displayName;
555  }
556 
557  @Override
558  public List<String> getFilter() {
559  return Collections.unmodifiableList(this.filter);
560  }
561  }
562 
563  // document sub-node filters
564  public static enum DocumentFilter implements AutopsyVisitableItem, SearchFilterInterface {
565 
566  AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS
567  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"),
568  Arrays.asList(".htm", ".html")), //NON-NLS
569  AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS
570  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"),
571  Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS
572  AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS
573  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autoDocPdfFilter.text"),
574  Arrays.asList(".pdf")), //NON-NLS
575  AUT_DOC_TXT(3, "AUT_DOC_TXT", //NON-NLS
576  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocTxtFilter.text"),
577  Arrays.asList(".txt")), //NON-NLS
578  AUT_DOC_RTF(4, "AUT_DOC_RTF", //NON-NLS
579  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
580  Arrays.asList(".rtf")); //NON-NLS
581 
582  private final int id;
583  private final String name;
584  private final String displayName;
585  private final List<String> filter;
586 
587  private DocumentFilter(int id, String name, String displayName, List<String> filter) {
588  this.id = id;
589  this.name = name;
590  this.displayName = displayName;
591  this.filter = filter;
592  }
593 
594  @Override
595  public <T> T accept(AutopsyItemVisitor<T> visitor) {
596  return visitor.visit(this);
597  }
598 
599  @Override
600  public String getName() {
601  return this.name;
602  }
603 
604  @Override
605  public int getId() {
606  return this.id;
607  }
608 
609  @Override
610  public String getDisplayName() {
611  return this.displayName;
612  }
613 
614  @Override
615  public List<String> getFilter() {
616  return Collections.unmodifiableList(this.filter);
617  }
618  }
619 
620  // executable sub-node filters
621  public static enum ExecutableFilter implements AutopsyVisitableItem, SearchFilterInterface {
622 
623  ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")), //NON-NLS
624  ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")), //NON-NLS
625  ExecutableFilter_BAT(2, "ExecutableFilter_BAT", ".bat", Arrays.asList(".bat")), //NON-NLS
626  ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
627  ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
628 
629  private final int id;
630  private final String name;
631  private final String displayName;
632  private final List<String> filter;
633 
634  private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
635  this.id = id;
636  this.name = name;
637  this.displayName = displayName;
638  this.filter = filter;
639  }
640 
641  @Override
642  public <T> T accept(AutopsyItemVisitor<T> visitor) {
643  return visitor.visit(this);
644  }
645 
646  @Override
647  public String getName() {
648  return this.name;
649  }
650 
651  @Override
652  public int getId() {
653  return this.id;
654  }
655 
656  @Override
657  public String getDisplayName() {
658  return this.displayName;
659  }
660 
661  @Override
662  public List<String> getFilter() {
663  return Collections.unmodifiableList(this.filter);
664  }
665  }
666 
667  interface SearchFilterInterface {
668 
669  public String getName();
670 
671  public int getId();
672 
673  public String getDisplayName();
674 
675  public List<String> getFilter();
676 
677  }
678 }
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:711
ExecutableFilter(int id, String name, String displayName, List< String > filter)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:756

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