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