Autopsy  4.17.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;
54 
62 public final class FileTypesByMimeType extends Observable implements AutopsyVisitableItem {
63 
64  private final static Logger logger = Logger.getLogger(FileTypesByMimeType.class.getName());
66  private final SleuthkitCase skCase;
72  private final HashMap<String, Map<String, Long>> existingMimeTypeCounts = new HashMap<>();
77  private final FileTypes typesRoot;
78 
83  private final PropertyChangeListener pcl;
84 
86 
92 
101  private String createBaseWhereExpr() {
102  return "(dir_type = " + TskData.TSK_FS_NAME_TYPE_ENUM.REG.getValue() + ")"
103  + " AND (type IN ("
104  + TskData.TSK_DB_FILES_TYPE_ENUM.FS.ordinal() + ","
105  + TskData.TSK_DB_FILES_TYPE_ENUM.CARVED.ordinal() + ","
106  + TskData.TSK_DB_FILES_TYPE_ENUM.DERIVED.ordinal() + ","
107  + TskData.TSK_DB_FILES_TYPE_ENUM.LAYOUT_FILE.ordinal() + ","
108  + TskData.TSK_DB_FILES_TYPE_ENUM.LOCAL.ordinal()
109  + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
110  + "))"
111  + ((filteringDataSourceObjId() > 0) ? " AND data_source_obj_id = " + this.filteringDataSourceObjId() : " ")
112  + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
113  }
114 
115  private void removeListeners() {
116  deleteObservers();
118  refreshThrottler.unregisterEventListener();
120  }
121 
126  private void populateHashMap() {
127  String query = "SELECT mime_type, count(*) AS count FROM tsk_files "
128  + " WHERE mime_type IS NOT null "
129  + " AND " + createBaseWhereExpr()
130  + " GROUP BY mime_type";
131  synchronized (existingMimeTypeCounts) {
132  existingMimeTypeCounts.clear();
133 
134  if (skCase == null) {
135  return;
136  }
137  try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
138  ResultSet resultSet = dbQuery.getResultSet();
139  while (resultSet.next()) {
140  final String mime_type = resultSet.getString("mime_type"); //NON-NLS
141  if (!mime_type.isEmpty()) {
142  //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
143  final String mediaType = StringUtils.substringBefore(mime_type, "/");
144  final String subType = StringUtils.removeStart(mime_type, mediaType + "/");
145  if (!mediaType.isEmpty() && !subType.isEmpty()) {
146  final long count = resultSet.getLong("count");
147  existingMimeTypeCounts.computeIfAbsent(mediaType, t -> new HashMap<>())
148  .put(subType, count);
149  }
150  }
151  }
152  } catch (TskCoreException | SQLException ex) {
153  logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
154  }
155  }
156 
157  setChanged();
158  notifyObservers();
159  }
160 
161  FileTypesByMimeType(FileTypes typesRoot) {
162  this.skCase = typesRoot.getSleuthkitCase();
163  this.typesRoot = typesRoot;
164  this.pcl = (PropertyChangeEvent evt) -> {
165  String eventType = evt.getPropertyName();
166  if (eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
167  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
168  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
169 
171  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
172  if (evt.getNewValue() == null) {
173  removeListeners();
174  }
175  }
176  };
177  refreshThrottler = new RefreshThrottler(new FileTypesByMimeTypeRefresher());
178  IngestManager.getInstance().addIngestJobEventListener(INGEST_JOB_EVENTS_OF_INTEREST, pcl);
179  refreshThrottler.registerForIngestModuleEvents();
180  Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
181  populateHashMap();
182  }
183 
184  @Override
185  public <T> T accept(AutopsyItemVisitor<T> visitor) {
186  return visitor.visit(this);
187  }
188 
189  long filteringDataSourceObjId() {
190  return typesRoot.filteringDataSourceObjId();
191  }
192 
202  public static boolean isEmptyMimeTypeNode(Node node) {
203  boolean isEmptyMimeNode = false;
204  if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
205  isEmptyMimeNode = true;
206  }
207  return isEmptyMimeNode;
208 
209  }
210 
211  private void refreshMimeTypes() {
217  try {
219  typesRoot.updateShowCounts();
220  populateHashMap();
221  } catch (NoCurrentCaseException notUsed) {
225  }
226  }
227 
232  private class FileTypesByMimeTypeRefresher implements RefreshThrottler.Refresher {
233 
234  @Override
235  public void refresh() {
237  }
238 
239  @Override
240  public boolean isRefreshRequired(PropertyChangeEvent evt) {
241  return true;
242  }
243 
244  }
245 
252  class ByMimeTypeNode extends DisplayableItemNode {
253 
254  @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
255 
256  final String NAME = Bundle.FileTypesByMimeType_name_text();
257 
258  ByMimeTypeNode() {
259  super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
260  super.setName(NAME);
261  super.setDisplayName(NAME);
262  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
263  }
264 
265  @Override
266  public boolean isLeafTypeNode() {
267  return false;
268  }
269 
270  @Override
271  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
272  return visitor.visit(this);
273  }
274 
275  @Override
276  public String getItemType() {
277  return getClass().getName();
278  }
279 
280  boolean isEmpty() {
281  synchronized (existingMimeTypeCounts) {
282  return existingMimeTypeCounts.isEmpty();
283  }
284  }
285  }
286 
291  private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
292 
294  super();
295  addObserver(this);
296  }
297 
298  @Override
299  protected boolean createKeys(List<String> mediaTypeNodes) {
300  final List<String> keylist;
301  synchronized (existingMimeTypeCounts) {
302  keylist = new ArrayList<>(existingMimeTypeCounts.keySet());
303  }
304  Collections.sort(keylist);
305  mediaTypeNodes.addAll(keylist);
306 
307  return true;
308  }
309 
310  @Override
311  protected Node createNodeForKey(String key) {
312  return new MediaTypeNode(key);
313  }
314 
315  @Override
316  public void update(Observable o, Object arg) {
317  refresh(true);
318  }
319  }
320 
325  class MediaTypeNode extends DisplayableItemNode {
326 
327  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type",
328  "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type",
329  "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"})
330 
331  MediaTypeNode(String name) {
332  super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
333  setName(name);
334  setDisplayName(name);
335  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
336  }
337 
338  @Override
339  public boolean isLeafTypeNode() {
340  return false;
341  }
342 
343  @Override
344  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
345  return visitor.visit(this);
346  }
347 
348  @Override
349  protected Sheet createSheet() {
350  Sheet sheet = super.createSheet();
351  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
352  if (sheetSet == null) {
353  sheetSet = Sheet.createPropertiesSet();
354  sheet.put(sheetSet);
355  }
356  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()));
357  return sheet;
358  }
359 
360  @Override
361  public String getItemType() {
362  return getClass().getName();
363  }
364 
365  }
366 
372  private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
373 
374  String mediaType;
375 
376  MediaTypeNodeChildren(String name) {
377  addObserver(this);
378  this.mediaType = name;
379  }
380 
381  @Override
382  protected boolean createKeys(List<String> mediaTypeNodes) {
383  mediaTypeNodes.addAll(existingMimeTypeCounts.get(mediaType).keySet());
384  return true;
385  }
386 
387  @Override
388  protected Node createNodeForKey(String subtype) {
389  String mimeType = mediaType + "/" + subtype;
390  return new MediaSubTypeNode(mimeType);
391  }
392 
393  @Override
394  public void update(Observable o, Object arg) {
395  refresh(true);
396  }
397 
398  }
399 
404  final class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
405 
406  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
407  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
408  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"})
409  private final String mimeType;
410  private final String subType;
411 
412  private MediaSubTypeNode(String mimeType) {
413  super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true), Lookups.singleton(mimeType));
414  this.mimeType = mimeType;
415  this.subType = StringUtils.substringAfter(mimeType, "/");
416  super.setName(mimeType);
417  super.setDisplayName(subType);
418  updateDisplayName();
419  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
420  addObserver(this);
421  }
422 
429  @Override
430  public boolean isLeafTypeNode() {
431  return true;
432  }
433 
434  @Override
435  public <T> T accept(DisplayableItemNodeVisitor< T> visitor) {
436  return visitor.visit(this);
437  }
438 
439  @Override
440  protected Sheet createSheet() {
441  Sheet sheet = super.createSheet();
442  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
443  if (sheetSet == null) {
444  sheetSet = Sheet.createPropertiesSet();
445  sheet.put(sheetSet);
446  }
447  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()));
448  return sheet;
449  }
450 
451  @Override
452  public String getItemType() {
453  return getClass().getName();
454  }
455 
456  @Override
457  public void update(Observable o, Object arg) {
458  updateDisplayName();
459  }
460 
461  @Override
462  String getDisplayNameBase() {
463  return subType;
464  }
465 
466  @Override
467  long calculateChildCount() {
468  return existingMimeTypeCounts.get(StringUtils.substringBefore(mimeType, "/")).get(subType);
469  }
470  }
471 
477  private class MediaSubTypeNodeChildren extends BaseChildFactory<FileTypesKey> implements Observer {
478 
479  private final String mimeType;
480 
481  private MediaSubTypeNodeChildren(String mimeType) {
482  super(mimeType, new ViewsKnownAndSlackFilter<>());
483  addObserver(this);
484  this.mimeType = mimeType;
485  }
486 
487  @Override
488  public void update(Observable o, Object arg) {
489  refresh(true);
490  }
491 
492  @Override
493  protected Node createNodeForKey(FileTypesKey key) {
494  return key.accept(new FileTypes.FileNodeCreationVisitor());
495  }
496 
497  @Override
498  protected List<FileTypesKey> makeKeys() {
499  try {
500  return skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
501  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList()); //NON-NLS
502  } catch (TskCoreException ex) {
503  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
504  }
505  return Collections.emptyList();
506  }
507 
508  @Override
509  protected void onAdd() {
510  // No-op
511  }
512 
513  @Override
514  protected void onRemove() {
515  // No-op
516  }
517  }
518 }
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:536

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