Autopsy  4.14.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
FileTypesByMimeType.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.sql.ResultSet;
24 import java.sql.SQLException;
25 import java.util.ArrayList;
26 import java.util.Collections;
27 import java.util.EnumSet;
28 import java.util.HashMap;
29 import java.util.List;
30 import java.util.Map;
31 import java.util.Observable;
32 import java.util.Observer;
33 import java.util.Set;
34 import java.util.logging.Level;
35 import java.util.stream.Collectors;
36 import org.apache.commons.lang3.StringUtils;
37 import org.openide.nodes.ChildFactory;
38 import org.openide.nodes.Children;
39 import org.openide.nodes.Node;
40 import org.openide.nodes.Sheet;
41 import org.openide.util.NbBundle;
42 import org.openide.util.lookup.Lookups;
50 import org.sleuthkit.datamodel.SleuthkitCase;
51 import org.sleuthkit.datamodel.TskCoreException;
52 import org.sleuthkit.datamodel.TskData;
53 
61 public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
62 
63  private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
65  private final SleuthkitCase skCase;
71  private final HashMap<String, Map<String, Long>> existingMimeTypeCounts = new HashMap<>();
76  private final FileTypes typesRoot;
77 
82  private final PropertyChangeListener pcl;
83 
85 
94  private String createBaseWhereExpr() {
95  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
96  + " AND (type IN ("
97  + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
98  + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
99  + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
100  + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + ","
101  + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
102  + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
103  + "))"
104  + ((filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
105  + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
106  }
107 
108  private void removeListeners() {
109  deleteObservers();
112  }
113 
118  private void populateHashMap() {
119  String query = "SELECT mime_type, count(*) AS count FROM tsk_files "
120  + " WHERE mime_type IS NOT null "
121  + " AND " + createBaseWhereExpr()
122  + " GROUP BY mime_type";
123  synchronized (existingMimeTypeCounts) {
124  existingMimeTypeCounts.clear();
125 
126  if (skCase == null) {
127  return;
128  }
129  try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
130  ResultSet resultSet = dbQuery.getResultSet();
131  while (resultSet.next()) {
132  final String mime_type = resultSet.getString("mime_type"); //NON-NLS
133  if (!mime_type.isEmpty()) {
134  //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
135  final String mediaType = StringUtils.substringBefore(mime_type, "/");
136  final String subType = StringUtils.removeStart(mime_type, mediaType + "/");
137  if (!mediaType.isEmpty() && !subType.isEmpty()) {
138  final long count = resultSet.getLong("count");
139  existingMimeTypeCounts.computeIfAbsent(mediaType, t -> new HashMap<>())
140  .put(subType, count);
141  }
142  }
143  }
144  } catch (TskCoreException | SQLException ex) {
145  logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
146  }
147  }
148 
149  setChanged();
150  notifyObservers();
151  }
152 
153  FileTypesByMimeType(FileTypes typesRoot) {
154  this.skCase = typesRoot.getSleuthkitCase();
155  this.typesRoot = typesRoot;
156  this.pcl = (PropertyChangeEvent evt) -> {
157  String eventType = evt.getPropertyName();
158  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
159  || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
160  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
161  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
168  try {
170  typesRoot.updateShowCounts();
171  populateHashMap();
172  } catch (NoCurrentCaseException notUsed) {
176  }
177  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
178  if (evt.getNewValue() == null) {
179  removeListeners();
180  }
181  }
182  };
183  IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
184  Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
185  populateHashMap();
186  }
187 
188  @Override
189  public <T> T accept(AutopsyItemVisitor<T> visitor) {
190  return visitor.visit(this);
191  }
192 
193  long filteringDataSourceObjId() {
194  return typesRoot.filteringDataSourceObjId();
195  }
196 
206  public static boolean isEmptyMimeTypeNode(Node node) {
207  boolean isEmptyMimeNode = false;
208  if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
209  isEmptyMimeNode = true;
210  }
211  return isEmptyMimeNode;
212 
213  }
214 
221  class ByMimeTypeNode extends DisplayableItemNode {
222 
223  @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
224 
225  final String NAME = Bundle.FileTypesByMimeType_name_text();
226 
227  ByMimeTypeNode() {
228  super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
229  super.setName(NAME);
230  super.setDisplayName(NAME);
231  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
232  }
233 
234  @Override
235  public boolean isLeafTypeNode() {
236  return false;
237  }
238 
239  @Override
240  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
241  return visitor.visit(this);
242  }
243 
244  @Override
245  public String getItemType() {
246  return getClass().getName();
247  }
248 
249  boolean isEmpty() {
250  synchronized (existingMimeTypeCounts) {
251  return existingMimeTypeCounts.isEmpty();
252  }
253  }
254  }
255 
260  private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
261 
263  super();
264  addObserver(this);
265  }
266 
267  @Override
268  protected boolean createKeys(List<String> mediaTypeNodes) {
269  final List<String> keylist;
270  synchronized (existingMimeTypeCounts) {
271  keylist = new ArrayList<>(existingMimeTypeCounts.keySet());
272  }
273  Collections.sort(keylist);
274  mediaTypeNodes.addAll(keylist);
275 
276  return true;
277  }
278 
279  @Override
280  protected Node createNodeForKey(String key) {
281  return new MediaTypeNode(key);
282  }
283 
284  @Override
285  public void update(Observable o, Object arg) {
286  refresh(true);
287  }
288  }
289 
294  class MediaTypeNode extends DisplayableItemNode {
295 
296  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type",
297  "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type",
298  "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"})
299 
300  MediaTypeNode(String name) {
301  super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
302  setName(name);
303  setDisplayName(name);
304  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
305  }
306 
307  @Override
308  public boolean isLeafTypeNode() {
309  return false;
310  }
311 
312  @Override
313  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
314  return visitor.visit(this);
315  }
316 
317  @Override
318  protected Sheet createSheet() {
319  Sheet sheet = super.createSheet();
320  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
321  if (sheetSet == null) {
322  sheetSet = Sheet.createPropertiesSet();
323  sheet.put(sheetSet);
324  }
325  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaType.desc"), getDisplayName()));
326  return sheet;
327  }
328 
329  @Override
330  public String getItemType() {
331  return getClass().getName();
332  }
333 
334  }
335 
341  private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
342 
343  String mediaType;
344 
345  MediaTypeNodeChildren(String name) {
346  addObserver(this);
347  this.mediaType = name;
348  }
349 
350  @Override
351  protected boolean createKeys(List<String> mediaTypeNodes) {
352  mediaTypeNodes.addAll(existingMimeTypeCounts.get(mediaType).keySet());
353  return true;
354  }
355 
356  @Override
357  protected Node createNodeForKey(String subtype) {
358  String mimeType = mediaType + "/" + subtype;
359  return new MediaSubTypeNode(mimeType);
360  }
361 
362  @Override
363  public void update(Observable o, Object arg) {
364  refresh(true);
365  }
366 
367  }
368 
373  final class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
374 
375  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
376  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
377  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"})
378  private final String mimeType;
379  private final String subType;
380 
381  private MediaSubTypeNode(String mimeType) {
382  super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true), Lookups.singleton(mimeType));
383  this.mimeType = mimeType;
384  this.subType = StringUtils.substringAfter(mimeType, "/");
385  super.setName(mimeType);
386  super.setDisplayName(subType);
387  updateDisplayName();
388  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
389  addObserver(this);
390  }
391 
398  @Override
399  public boolean isLeafTypeNode() {
400  return true;
401  }
402 
403  @Override
404  public <T> T accept(DisplayableItemNodeVisitor< T> visitor) {
405  return visitor.visit(this);
406  }
407 
408  @Override
409  protected Sheet createSheet() {
410  Sheet sheet = super.createSheet();
411  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
412  if (sheetSet == null) {
413  sheetSet = Sheet.createPropertiesSet();
414  sheet.put(sheetSet);
415  }
416  sheetSet.put(new NodeProperty<>(NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.name"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName"), NbBundle.getMessage(this.getClass(), "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc"), getDisplayName()));
417  return sheet;
418  }
419 
420  @Override
421  public String getItemType() {
422  return getClass().getName();
423  }
424 
425  @Override
426  public void update(Observable o, Object arg) {
427  updateDisplayName();
428  }
429 
430  @Override
431  String getDisplayNameBase() {
432  return subType;
433  }
434 
435  @Override
436  long calculateChildCount() {
437  return existingMimeTypeCounts.get(StringUtils.substringBefore(mimeType, "/")).get(subType);
438  }
439  }
440 
446  private class MediaSubTypeNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
447 
448  private final String mimeType;
449 
450  private MediaSubTypeNodeChildren(String mimeType) {
451  super(mimeType, new ViewsKnownAndSlackFilter<>());
452  addObserver(this);
453  this.mimeType = mimeType;
454  }
455 
456  @Override
457  public void update(Observable o, Object arg) {
458  refresh(true);
459  }
460 
461  @Override
462  protected Node createNodeForKey(FileTypesKey key) {
463  return key.accept(new FileTypes.FileNodeCreationVisitor());
464  }
465 
466  @Override
467  protected List<FileTypesKey> makeKeys() {
468  try {
469  return skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
470  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()); //NON-NLS
471  } catch (TskCoreException ex) {
472  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
473  }
474  return Collections.emptyList();
475  }
476 
477  @Override
478  protected void onAdd() {
479  // No-op
480  }
481 
482  @Override
483  protected void onRemove() {
484  // No-op
485  }
486  }
487 }
static synchronized IngestManager getInstance()
void removeIngestJobEventListener(final PropertyChangeListener listener)
final HashMap< String, Map< String, Long > > existingMimeTypeCounts
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static final Set< IngestManager.IngestJobEvent > INGEST_JOB_EVENTS_OF_INTEREST
static void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:531

Copyright © 2012-2020 Basis Technology. Generated on: Wed Apr 8 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.