Autopsy  4.13.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;
46 import org.sleuthkit.datamodel.SleuthkitCase;
47 import org.sleuthkit.datamodel.TskCoreException;
48 import org.sleuthkit.datamodel.TskData;
49 
53 public final class FileTypesByExtension implements AutopsyVisitableItem {
54 
55  private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
58  private final SleuthkitCase skCase;
59  private final FileTypes typesRoot;
60 
61  public FileTypesByExtension(FileTypes typesRoot) {
62  this.skCase = typesRoot.getSleuthkitCase();
63  this.typesRoot = typesRoot;
64  }
65 
66  public SleuthkitCase getSleuthkitCase() {
67  return this.skCase;
68  }
69 
70  @Override
71  public <T> T accept(AutopsyItemVisitor<T> visitor) {
72  return visitor.visit(this);
73  }
74 
75  long filteringDataSourceObjId() {
76  return typesRoot.filteringDataSourceObjId();
77  }
78 
83  private class FileTypesByExtObservable extends Observable {
84 
85  private final PropertyChangeListener pcl;
86  private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
87 
89  super();
91  this.pcl = (PropertyChangeEvent evt) -> {
92  String eventType = evt.getPropertyName();
93  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
94  || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
95  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
96  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
103  try {
105  typesRoot.updateShowCounts();
106  update();
107  } catch (NoCurrentCaseException notUsed) {
111  }
112  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
113  // case was closed. Remove listeners so that we don't get called with a stale case handle
114  if (evt.getNewValue() == null) {
115  removeListeners();
116  }
117  }
118  };
119 
123  }
124 
125  private void removeListeners() {
126  deleteObservers();
130  }
131 
132  private void update() {
133  setChanged();
134  notifyObservers();
135  }
136  }
137  private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
138 
142  class FileTypesByExtNode extends DisplayableItemNode {
143 
144  private final FileTypesByExtension.RootFilter filter;
145 
152  FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) {
153  this(skCase, filter, null);
154  }
155 
163  private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
164 
165  super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true),
166  Lookups.singleton(filter == null ? FNAME : filter.getDisplayName()));
167  this.filter = filter;
168 
169  // root node of tree
170  if (filter == null) {
171  super.setName(FNAME);
172  super.setDisplayName(FNAME);
173  } // sub-node in file tree (i.e. documents, exec, etc.)
174  else {
175  super.setName(filter.getDisplayName());
176  super.setDisplayName(filter.getDisplayName());
177  }
178  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
179  }
180 
181  @Override
182  public boolean isLeafTypeNode() {
183  return false;
184  }
185 
186  @Override
187  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
188  return visitor.visit(this);
189  }
190 
191  @Override
192  protected Sheet createSheet() {
193  Sheet sheet = super.createSheet();
194  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
195  if (sheetSet == null) {
196  sheetSet = Sheet.createPropertiesSet();
197  sheet.put(sheetSet);
198  }
199  if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) {
200  String extensions = "";
201  for (String ext : filter.getFilter()) {
202  extensions += "'" + ext + "', ";
203  }
204  extensions = extensions.substring(0, extensions.lastIndexOf(','));
205  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));
206  } else {
207  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()));
208  }
209  return sheet;
210  }
211 
212  @Override
213  public String getItemType() {
218  if (filter == null) {
219  return getClass().getName();
220  }
222  return getClass().getName() + filter.getName();
223  }
224  return getClass().getName();
225  }
226 
227  }
228 
229  private class FileTypesByExtNodeChildren extends ChildFactory<FileTypesByExtension.SearchFilterInterface> {
230 
231  private final SleuthkitCase skCase;
234 
243  super();
244  this.skCase = skCase;
245  this.filter = filter;
246  if (o == null) {
247  this.notifier = new FileTypesByExtObservable();
248  } else {
249  this.notifier = o;
250  }
251  }
252 
253  @Override
254  protected boolean createKeys(List<FileTypesByExtension.SearchFilterInterface> list) {
255  // root node
256  if (filter == null) {
257  list.addAll(Arrays.asList(FileTypesByExtension.RootFilter.values()));
258  } // document and executable has another level of nodes
260  list.addAll(Arrays.asList(FileTypesByExtension.DocumentFilter.values()));
262  list.addAll(Arrays.asList(FileTypesByExtension.ExecutableFilter.values()));
263  }
264  return true;
265  }
266 
267  @Override
269  // make new nodes for the sub-nodes
270  if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
271  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER, notifier);
272  } else if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
273  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
274  } else {
275  return new FileExtensionNode(key, skCase, notifier);
276  }
277  }
278  }
279 
284  final class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
285 
286  private final FileTypesByExtension.SearchFilterInterface filter;
287 
295  FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
296  super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o, filter.getDisplayName()), true),
297  Lookups.singleton(filter.getDisplayName()));
298  this.filter = filter;
299  super.setName(filter.getDisplayName());
300  updateDisplayName();
301  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
302 
303  o.addObserver(this);
304  }
305 
306  @Override
307  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
308  return visitor.visit(this);
309  }
310 
311  @Override
312  protected Sheet createSheet() {
313  Sheet sheet = super.createSheet();
314  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
315  if (sheetSet == null) {
316  sheetSet = Sheet.createPropertiesSet();
317  sheet.put(sheetSet);
318  }
319  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"),
320  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"),
321  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"),
322  filter.getDisplayName()));
323 
324  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"),
325  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"),
326  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"),
327  String.join(", ", filter.getFilter())));
328  return sheet;
329  }
330 
331  @Override
332  public boolean isLeafTypeNode() {
333  return true;
334  }
335 
341  @Override
342  public String getItemType() {
343  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
344  }
345 
346  @Override
347  String getDisplayNameBase() {
348  return filter.getDisplayName();
349  }
350 
351  @Override
352  long calculateChildCount() throws TskCoreException {
353  return skCase.countFilesWhere(createQuery(filter));
354  }
355  }
356 
358  if (filter.getFilter().isEmpty()) {
359  // We should never be given a search filter without extensions
360  // but if we are it is clearly a programming error so we throw
361  // an IllegalArgumentException.
362  throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
363  }
364 
365  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
367  ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
368  : " ")
369  + (filteringDataSourceObjId() > 0
370  ? " AND data_source_obj_id = " + filteringDataSourceObjId()
371  : " ")
372  + " AND (extension IN (" + filter.getFilter().stream()
373  .map(String::toLowerCase)
374  .map(s -> "'" + StringUtils.substringAfter(s, ".") + "'")
375  .collect(Collectors.joining(", ")) + "))";
376  }
377 
381  private class FileExtensionNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
382 
383  private final SleuthkitCase skCase;
385  private final Observable notifier;
386 
395  private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o, String nodeName) {
396  super(nodeName, new ViewsKnownAndSlackFilter<>());
397  this.filter = filter;
398  this.skCase = skCase;
399  notifier = o;
400  }
401 
402  @Override
403  protected void onAdd() {
404  if (notifier != null) {
405  notifier.addObserver(this);
406  }
407  }
408 
409  @Override
410  protected void onRemove() {
411  if (notifier != null) {
412  notifier.deleteObserver(this);
413  }
414  }
415 
416  @Override
417  public void update(Observable o, Object arg) {
418  refresh(true);
419  }
420 
421  @Override
422  protected Node createNodeForKey(FileTypesKey key) {
423  return key.accept(new FileTypes.FileNodeCreationVisitor());
424  }
425 
426  @Override
427  protected List<FileTypesKey> makeKeys() {
428  try {
429  return skCase.findAllFilesWhere(createQuery(filter))
430  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList());
431  } catch (TskCoreException ex) {
432  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
433  }
434  return Collections.emptyList();
435  }
436  }
437 
438  // root node filters
439  @Messages({"FileTypeExtensionFilters.tskDatabaseFilter.text=Databases"})
440  public static enum RootFilter implements AutopsyVisitableItem, SearchFilterInterface {
441 
442  TSK_IMAGE_FILTER(0, "TSK_IMAGE_FILTER", //NON-NLS
443  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskImgFilter.text"),
445  TSK_VIDEO_FILTER(1, "TSK_VIDEO_FILTER", //NON-NLS
446  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskVideoFilter.text"),
448  TSK_AUDIO_FILTER(2, "TSK_AUDIO_FILTER", //NON-NLS
449  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskAudioFilter.text"),
451  TSK_ARCHIVE_FILTER(3, "TSK_ARCHIVE_FILTER", //NON-NLS
452  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskArchiveFilter.text"),
454  TSK_DATABASE_FILTER(4, "TSK_DATABASE_FILTER", //NON-NLS
455  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDatabaseFilter.text"),
457  TSK_DOCUMENT_FILTER(5, "TSK_DOCUMENT_FILTER", //NON-NLS
458  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskDocumentFilter.text"),
459  Arrays.asList(".htm", ".html", ".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx", ".pdf", ".txt", ".rtf")), //NON-NLS
460  TSK_EXECUTABLE_FILTER(6, "TSK_EXECUTABLE_FILTER", //NON-NLS
461  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.tskExecFilter.text"),
463 
464  private final int id;
465  private final String name;
466  private final String displayName;
467  private final List<String> filter;
468 
469  private RootFilter(int id, String name, String displayName, List<String> filter) {
470  this.id = id;
471  this.name = name;
472  this.displayName = displayName;
473  this.filter = filter;
474  }
475 
476  @Override
477  public <T> T accept(AutopsyItemVisitor<T> visitor) {
478  return visitor.visit(this);
479  }
480 
481  @Override
482  public String getName() {
483  return this.name;
484  }
485 
486  @Override
487  public int getId() {
488  return this.id;
489  }
490 
491  @Override
492  public String getDisplayName() {
493  return this.displayName;
494  }
495 
496  @Override
497  public List<String> getFilter() {
498  return Collections.unmodifiableList(this.filter);
499  }
500  }
501 
502  // document sub-node filters
503  public static enum DocumentFilter implements AutopsyVisitableItem, SearchFilterInterface {
504 
505  AUT_DOC_HTML(0, "AUT_DOC_HTML", //NON-NLS
506  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocHtmlFilter.text"),
507  Arrays.asList(".htm", ".html")), //NON-NLS
508  AUT_DOC_OFFICE(1, "AUT_DOC_OFFICE", //NON-NLS
509  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocOfficeFilter.text"),
510  Arrays.asList(".doc", ".docx", ".odt", ".xls", ".xlsx", ".ppt", ".pptx")), //NON-NLS
511  AUT_DOC_PDF(2, "AUT_DOC_PDF", //NON-NLS
512  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autoDocPdfFilter.text"),
513  Arrays.asList(".pdf")), //NON-NLS
514  AUT_DOC_TXT(3, "AUT_DOC_TXT", //NON-NLS
515  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocTxtFilter.text"),
516  Arrays.asList(".txt")), //NON-NLS
517  AUT_DOC_RTF(4, "AUT_DOC_RTF", //NON-NLS
518  NbBundle.getMessage(FileTypesByExtension.class, "FileTypeExtensionFilters.autDocRtfFilter.text"),
519  Arrays.asList(".rtf")); //NON-NLS
520 
521  private final int id;
522  private final String name;
523  private final String displayName;
524  private final List<String> filter;
525 
526  private DocumentFilter(int id, String name, String displayName, List<String> filter) {
527  this.id = id;
528  this.name = name;
529  this.displayName = displayName;
530  this.filter = filter;
531  }
532 
533  @Override
534  public <T> T accept(AutopsyItemVisitor<T> visitor) {
535  return visitor.visit(this);
536  }
537 
538  @Override
539  public String getName() {
540  return this.name;
541  }
542 
543  @Override
544  public int getId() {
545  return this.id;
546  }
547 
548  @Override
549  public String getDisplayName() {
550  return this.displayName;
551  }
552 
553  @Override
554  public List<String> getFilter() {
555  return Collections.unmodifiableList(this.filter);
556  }
557  }
558 
559  // executable sub-node filters
560  public static enum ExecutableFilter implements AutopsyVisitableItem, SearchFilterInterface {
561 
562  ExecutableFilter_EXE(0, "ExecutableFilter_EXE", ".exe", Arrays.asList(".exe")), //NON-NLS
563  ExecutableFilter_DLL(1, "ExecutableFilter_DLL", ".dll", Arrays.asList(".dll")), //NON-NLS
564  ExecutableFilter_BAT(2, "ExecutableFilter_BAT", ".bat", Arrays.asList(".bat")), //NON-NLS
565  ExecutableFilter_CMD(3, "ExecutableFilter_CMD", ".cmd", Arrays.asList(".cmd")), //NON-NLS
566  ExecutableFilter_COM(4, "ExecutableFilter_COM", ".com", Arrays.asList(".com")); //NON-NLS
567 
568  private final int id;
569  private final String name;
570  private final String displayName;
571  private final List<String> filter;
572 
573  private ExecutableFilter(int id, String name, String displayName, List<String> filter) {
574  this.id = id;
575  this.name = name;
576  this.displayName = displayName;
577  this.filter = filter;
578  }
579 
580  @Override
581  public <T> T accept(AutopsyItemVisitor<T> visitor) {
582  return visitor.visit(this);
583  }
584 
585  @Override
586  public String getName() {
587  return this.name;
588  }
589 
590  @Override
591  public int getId() {
592  return this.id;
593  }
594 
595  @Override
596  public String getDisplayName() {
597  return this.displayName;
598  }
599 
600  @Override
601  public List<String> getFilter() {
602  return Collections.unmodifiableList(this.filter);
603  }
604  }
605 
606  interface SearchFilterInterface {
607 
608  public String getName();
609 
610  public int getId();
611 
612  public String getDisplayName();
613 
614  public List<String> getFilter();
615 
616  }
617 }
void removeIngestModuleEventListener(final PropertyChangeListener listener)
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)
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:486
ExecutableFilter(int id, String name, String displayName, List< String > filter)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:531

Copyright © 2012-2019 Basis Technology. Generated on: Tue Jan 7 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.