Autopsy  4.10.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-2018 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.EnumSet;
25 import java.util.List;
26 import java.util.Objects;
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.SleuthkitCase;
48 import org.sleuthkit.datamodel.TskCoreException;
49 import org.sleuthkit.datamodel.TskData;
50 
54 public final class FileTypesByExtension implements AutopsyVisitableItem {
55 
56  private final static Logger logger = Logger.getLogger(FileTypesByExtension.class.getName());
57  private final SleuthkitCase skCase;
58  private final FileTypes typesRoot;
59 
60  public FileTypesByExtension(FileTypes typesRoot) {
61  this.skCase = typesRoot.getSleuthkitCase();
62  this.typesRoot = typesRoot;
63  }
64 
65  public SleuthkitCase getSleuthkitCase() {
66  return this.skCase;
67  }
68 
69  @Override
70  public <T> T accept(AutopsyItemVisitor<T> visitor) {
71  return visitor.visit(this);
72  }
73 
74  long filteringDataSourceObjId() {
75  return typesRoot.filteringDataSourceObjId();
76  }
77 
82  private class FileTypesByExtObservable extends Observable {
83 
84  private final PropertyChangeListener pcl;
85  private final Set<Case.Events> CASE_EVENTS_OF_INTEREST;
86 
88  super();
90  this.pcl = (PropertyChangeEvent evt) -> {
91  String eventType = evt.getPropertyName();
92  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
93  || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
94  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
95  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
102  try {
104  typesRoot.updateShowCounts();
105  update();
106  } catch (NoCurrentCaseException notUsed) {
110  }
111  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
112  // case was closed. Remove listeners so that we don't get called with a stale case handle
113  if (evt.getNewValue() == null) {
114  removeListeners();
115  }
116  }
117  };
118 
122  }
123 
124  private void removeListeners() {
125  deleteObservers();
129  }
130 
131  private void update() {
132  setChanged();
133  notifyObservers();
134  }
135  }
136  private static final String FNAME = NbBundle.getMessage(FileTypesByExtNode.class, "FileTypesByExtNode.fname.text");
137 
141  class FileTypesByExtNode extends DisplayableItemNode {
142 
143  private final FileTypesByExtension.RootFilter filter;
144 
151  FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter) {
152  this(skCase, filter, null);
153  }
154 
162  private FileTypesByExtNode(SleuthkitCase skCase, FileTypesByExtension.RootFilter filter, FileTypesByExtObservable o) {
163 
164  super(Children.create(new FileTypesByExtNodeChildren(skCase, filter, o), true),
165  Lookups.singleton(filter == null ? FNAME : filter.getDisplayName()));
166  this.filter = filter;
167 
168  // root node of tree
169  if (filter == null) {
170  super.setName(FNAME);
171  super.setDisplayName(FNAME);
172  } // sub-node in file tree (i.e. documents, exec, etc.)
173  else {
174  super.setName(filter.getDisplayName());
175  super.setDisplayName(filter.getDisplayName());
176  }
177  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png"); //NON-NLS
178  }
179 
180  @Override
181  public boolean isLeafTypeNode() {
182  return false;
183  }
184 
185  @Override
186  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
187  return visitor.visit(this);
188  }
189 
190  @Override
191  protected Sheet createSheet() {
192  Sheet sheet = super.createSheet();
193  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
194  if (sheetSet == null) {
195  sheetSet = Sheet.createPropertiesSet();
196  sheet.put(sheetSet);
197  }
198  if (filter != null && (filter.equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER) || filter.equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER))) {
199  String extensions = "";
200  for (String ext : filter.getFilter()) {
201  extensions += "'" + ext + "', ";
202  }
203  extensions = extensions.substring(0, extensions.lastIndexOf(','));
204  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));
205  } else {
206  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()));
207  }
208  return sheet;
209  }
210 
211  @Override
212  public String getItemType() {
217  if (filter == null) {
218  return getClass().getName();
219  }
221  return getClass().getName() + filter.getName();
222  }
223  return getClass().getName();
224  }
225 
226  }
227 
228  private class FileTypesByExtNodeChildren extends ChildFactory<FileTypesByExtension.SearchFilterInterface> {
229 
230  private final SleuthkitCase skCase;
233 
242  super();
243  this.skCase = skCase;
244  this.filter = filter;
245  if (o == null) {
246  this.notifier = new FileTypesByExtObservable();
247  } else {
248  this.notifier = o;
249  }
250  }
251 
252  @Override
253  protected boolean createKeys(List<FileTypesByExtension.SearchFilterInterface> list) {
254  // root node
255  if (filter == null) {
256  list.addAll(Arrays.asList(FileTypesByExtension.RootFilter.values()));
257  } // document and executable has another level of nodes
259  list.addAll(Arrays.asList(FileTypesByExtension.DocumentFilter.values()));
261  list.addAll(Arrays.asList(FileTypesByExtension.ExecutableFilter.values()));
262  }
263  return true;
264  }
265 
266  @Override
268  // make new nodes for the sub-nodes
269  if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER.getName())) {
270  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_DOCUMENT_FILTER, notifier);
271  } else if (key.getName().equals(FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER.getName())) {
272  return new FileTypesByExtNode(skCase, FileTypesByExtension.RootFilter.TSK_EXECUTABLE_FILTER, notifier);
273  } else {
274  return new FileExtensionNode(key, skCase, notifier);
275  }
276  }
277  }
278 
283  class FileExtensionNode extends FileTypes.BGCountUpdatingNode {
284 
285  private final FileTypesByExtension.SearchFilterInterface filter;
286 
294  FileExtensionNode(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, FileTypesByExtObservable o) {
295  super(typesRoot, Children.create(new FileExtensionNodeChildren(filter, skCase, o), true),
296  Lookups.singleton(filter.getDisplayName()));
297  this.filter = filter;
298  super.setName(filter.getDisplayName());
299  updateDisplayName();
300  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
301 
302  o.addObserver(this);
303  }
304 
305  @Override
306  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
307  return visitor.visit(this);
308  }
309 
310  @Override
311  protected Sheet createSheet() {
312  Sheet sheet = super.createSheet();
313  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
314  if (sheetSet == null) {
315  sheetSet = Sheet.createPropertiesSet();
316  sheet.put(sheetSet);
317  }
318  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.name"),
319  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.displayName"),
320  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.filterType.desc"),
321  filter.getDisplayName()));
322 
323  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.name"),
324  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.displayName"),
325  NbBundle.getMessage(this.getClass(), "FileTypesByExtNode.createSheet.fileExt.desc"),
326  String.join(", ", filter.getFilter())));
327  return sheet;
328  }
329 
330  @Override
331  public boolean isLeafTypeNode() {
332  return true;
333  }
334 
340  @Override
341  public String getItemType() {
342  return DisplayableItemNode.FILE_PARENT_NODE_KEY;
343  }
344 
345  @Override
346  String getDisplayNameBase() {
347  return filter.getDisplayName();
348  }
349 
350  @Override
351  long calculateChildCount() throws TskCoreException {
352  return skCase.countFilesWhere(createQuery(filter));
353  }
354  }
355 
357  if (filter.getFilter().isEmpty()) {
358  // We should never be given a search filter without extensions
359  // but if we are it is clearly a programming error so we throw
360  // an IllegalArgumentException.
361  throw new IllegalArgumentException("Empty filter list passed to createQuery()"); // NON-NLS
362  }
363 
364  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
366  ? " AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")"
367  : " ")
368  + (Objects.equals(CasePreferences.getGroupItemsInTreeByDataSource(), true)
369  ? " AND data_source_obj_id = " + filteringDataSourceObjId()
370  : " ")
371  + " AND (extension IN (" + filter.getFilter().stream()
372  .map(String::toLowerCase)
373  .map(s -> "'"+StringUtils.substringAfter(s, ".")+"'")
374  .collect(Collectors.joining(", ")) + "))";
375  }
376 
380  private class FileExtensionNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
381 
382  private final SleuthkitCase skCase;
384  private final Observable notifier;
385 
393  private FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o) {
394  super();
395  this.filter = filter;
396  this.skCase = skCase;
397  notifier = o;
398  }
399 
400  @Override
401  protected void addNotify() {
402  if (notifier != null) {
403  notifier.addObserver(this);
404  }
405  }
406 
407  @Override
408  protected void removeNotify() {
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 boolean createKeys(List<FileTypesKey> list) {
421  try {
422  list.addAll(skCase.findAllFilesWhere(createQuery(filter))
423  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()));
424  } catch (TskCoreException ex) {
425  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
426  }
427  return true;
428  }
429 
430  @Override
431  protected Node createNodeForKey(FileTypesKey key) {
432  return key.accept(new FileTypes.FileNodeCreationVisitor());
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)
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)
FileExtensionNodeChildren(FileTypesByExtension.SearchFilterInterface filter, SleuthkitCase skCase, Observable o)
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static void addEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:437
ExecutableFilter(int id, String name, String displayName, List< String > filter)
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:482

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