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

Copyright © 2012-2018 Basis Technology. Generated on: Fri Jun 21 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.