Autopsy  4.6.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-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.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());
64 
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  static 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.LOCAL.ordinal()
101  + (hideSlackFilesInViewsTree() ? "" : ("," + TskData.TSK_DB_FILES_TYPE_ENUM.SLACK.ordinal()))
102  + "))"
103  + (hideKnownFilesInViewsTree() ? (" AND (known IS NULL OR known != " + TskData.FileKnown.KNOWN.getFileKnownValue() + ")") : "");
104  }
105 
106  private void removeListeners() {
107  deleteObservers();
110  }
111 
116  private void populateHashMap() {
117  String query = "SELECT mime_type, count(*) AS count FROM tsk_files "
118  + " WHERE mime_type IS NOT null "
119  + " AND " + createBaseWhereExpr()
120  + " GROUP BY mime_type";
121  synchronized (existingMimeTypeCounts) {
122  existingMimeTypeCounts.clear();
123 
124  if (skCase == null) {
125  return;
126  }
127  try (SleuthkitCase.CaseDbQuery dbQuery = skCase.executeQuery(query)) {
128  ResultSet resultSet = dbQuery.getResultSet();
129  while (resultSet.next()) {
130  final String mime_type = resultSet.getString("mime_type"); //NON-NLS
131  if (!mime_type.isEmpty()) {
132  //if the mime_type contained multiple slashes then everything after the first slash will become the subtype
133  final String mediaType = StringUtils.substringBefore(mime_type, "/");
134  final String subType = StringUtils.removeStart(mime_type, mediaType + "/");
135  if (!mediaType.isEmpty() && !subType.isEmpty()) {
136  final long count = resultSet.getLong("count");
137  existingMimeTypeCounts.computeIfAbsent(mediaType, t -> new HashMap<>())
138  .put(subType, count);
139  }
140  }
141  }
142  } catch (TskCoreException | SQLException ex) {
143  logger.log(Level.SEVERE, "Unable to populate File Types by MIME Type tree view from DB: ", ex); //NON-NLS
144  }
145  }
146 
147  setChanged();
148  notifyObservers();
149  }
150 
151  FileTypesByMimeType(FileTypes typesRoot) {
152  this.skCase = typesRoot.getSleuthkitCase();
153  this.typesRoot = typesRoot;
154  this.pcl = (PropertyChangeEvent evt) -> {
155  String eventType = evt.getPropertyName();
156  if (eventType.equals(IngestManager.IngestModuleEvent.CONTENT_CHANGED.toString())
157  || eventType.equals(IngestManager.IngestJobEvent.COMPLETED.toString())
158  || eventType.equals(IngestManager.IngestJobEvent.CANCELLED.toString())
159  || eventType.equals(Case.Events.DATA_SOURCE_ADDED.toString())) {
166  try {
167  Case.getOpenCase();
168  typesRoot.updateShowCounts();
169  populateHashMap();
170  } catch (NoCurrentCaseException notUsed) {
174  }
175  } else if (eventType.equals(Case.Events.CURRENT_CASE.toString())) {
176  if (evt.getNewValue() == null) {
177  removeListeners();
178  }
179  }
180  };
181  IngestManager.getInstance().addIngestJobEventListener(pcl);
182  Case.addEventTypeSubscriber(CASE_EVENTS_OF_INTEREST, pcl);
183  populateHashMap();
184  }
185 
186  @Override
187  public <T> T accept(AutopsyItemVisitor<T> visitor) {
188  return visitor.visit(this);
189  }
190 
200  public static boolean isEmptyMimeTypeNode(Node node) {
201  boolean isEmptyMimeNode = false;
202  if (node instanceof FileTypesByMimeType.ByMimeTypeNode && ((FileTypesByMimeType.ByMimeTypeNode) node).isEmpty()) {
203  isEmptyMimeNode = true;
204  }
205  return isEmptyMimeNode;
206 
207  }
208 
215  class ByMimeTypeNode extends DisplayableItemNode {
216 
217  @NbBundle.Messages({"FileTypesByMimeType.name.text=By MIME Type"})
218 
219  final String NAME = Bundle.FileTypesByMimeType_name_text();
220 
221  ByMimeTypeNode() {
222  super(Children.create(new ByMimeTypeNodeChildren(), true), Lookups.singleton(Bundle.FileTypesByMimeType_name_text()));
223  super.setName(NAME);
224  super.setDisplayName(NAME);
225  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
226  }
227 
228  @Override
229  public boolean isLeafTypeNode() {
230  return false;
231  }
232 
233  @Override
234  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
235  return visitor.visit(this);
236  }
237 
238  @Override
239  public String getItemType() {
240  return getClass().getName();
241  }
242 
243  boolean isEmpty() {
244  synchronized (existingMimeTypeCounts) {
245  return existingMimeTypeCounts.isEmpty();
246  }
247  }
248  }
249 
254  private class ByMimeTypeNodeChildren extends ChildFactory<String> implements Observer {
255 
257  super();
258  addObserver(this);
259  }
260 
261  @Override
262  protected boolean createKeys(List<String> mediaTypeNodes) {
263  final List<String> keylist;
264  synchronized (existingMimeTypeCounts) {
265  keylist = new ArrayList<>(existingMimeTypeCounts.keySet());
266  }
267  Collections.sort(keylist);
268  mediaTypeNodes.addAll(keylist);
269 
270  return true;
271  }
272 
273  @Override
274  protected Node createNodeForKey(String key) {
275  return new MediaTypeNode(key);
276  }
277 
278  @Override
279  public void update(Observable o, Object arg) {
280  refresh(true);
281  }
282  }
283 
288  class MediaTypeNode extends DisplayableItemNode {
289 
290  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaType.name=Type",
291  "FileTypesByMimeTypeNode.createSheet.mediaType.displayName=Type",
292  "FileTypesByMimeTypeNode.createSheet.mediaType.desc=no description"})
293 
294  MediaTypeNode(String name) {
295  super(Children.create(new MediaTypeNodeChildren(name), true), Lookups.singleton(name));
296  setName(name);
297  setDisplayName(name);
298  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file_types.png");
299  }
300 
301  @Override
302  public boolean isLeafTypeNode() {
303  return false;
304  }
305 
306  @Override
307  public <T> T accept(DisplayableItemNodeVisitor<T> visitor) {
308  return visitor.visit(this);
309  }
310 
311  @Override
312  protected Sheet createSheet() {
313  Sheet sheet = super.createSheet();
314  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
315  if (sheetSet == null) {
316  sheetSet = Sheet.createPropertiesSet();
317  sheet.put(sheetSet);
318  }
319  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()));
320  return sheet;
321  }
322 
323  @Override
324  public String getItemType() {
325  return getClass().getName();
326  }
327 
328  }
329 
335  private class MediaTypeNodeChildren extends ChildFactory<String> implements Observer {
336 
337  String mediaType;
338 
339  MediaTypeNodeChildren(String name) {
340  addObserver(this);
341  this.mediaType = name;
342  }
343 
344  @Override
345  protected boolean createKeys(List<String> mediaTypeNodes) {
346  mediaTypeNodes.addAll(existingMimeTypeCounts.get(mediaType).keySet());
347  return true;
348  }
349 
350  @Override
351  protected Node createNodeForKey(String subtype) {
352  String mimeType = mediaType + "/" + subtype;
353  return new MediaSubTypeNode(mimeType);
354  }
355 
356  @Override
357  public void update(Observable o, Object arg) {
358  refresh(true);
359  }
360 
361  }
362 
367  class MediaSubTypeNode extends FileTypes.BGCountUpdatingNode {
368 
369  @NbBundle.Messages({"FileTypesByMimeTypeNode.createSheet.mediaSubtype.name=Subtype",
370  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.displayName=Subtype",
371  "FileTypesByMimeTypeNode.createSheet.mediaSubtype.desc=no description"})
372  private final String mimeType;
373  private final String subType;
374 
375  private MediaSubTypeNode(String mimeType) {
376  super(typesRoot, Children.create(new MediaSubTypeNodeChildren(mimeType), true), Lookups.singleton(mimeType));
377  this.mimeType = mimeType;
378  this.subType = StringUtils.substringAfter(mimeType, "/");
379  super.setName(mimeType);
380  super.setDisplayName(subType);
381  updateDisplayName();
382  this.setIconBaseWithExtension("org/sleuthkit/autopsy/images/file-filter-icon.png"); //NON-NLS
383  addObserver(this);
384  }
385 
392  @Override
393  public boolean isLeafTypeNode() {
394  return true;
395  }
396 
397  @Override
398  public <T> T accept(DisplayableItemNodeVisitor< T> visitor) {
399  return visitor.visit(this);
400  }
401 
402  @Override
403  protected Sheet createSheet() {
404  Sheet sheet = super.createSheet();
405  Sheet.Set sheetSet = sheet.get(Sheet.PROPERTIES);
406  if (sheetSet == null) {
407  sheetSet = Sheet.createPropertiesSet();
408  sheet.put(sheetSet);
409  }
410  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()));
411  return sheet;
412  }
413 
414  @Override
415  public String getItemType() {
416  return getClass().getName();
417  }
418 
419  @Override
420  public void update(Observable o, Object arg) {
421  updateDisplayName();
422  }
423 
424  @Override
425  String getDisplayNameBase() {
426  return subType;
427  }
428 
429  @Override
430  long calculateChildCount() {
431  return existingMimeTypeCounts.get(StringUtils.substringBefore(mimeType, "/")).get(subType);
432  }
433  }
434 
440  private class MediaSubTypeNodeChildren extends ChildFactory.Detachable<FileTypesKey> implements Observer {
441 
442  private final String mimeType;
443 
444  private MediaSubTypeNodeChildren(String mimeType) {
445  super();
446  addObserver(this);
447  this.mimeType = mimeType;
448  }
449 
450  @Override
451  protected boolean createKeys(List<FileTypesKey> list) {
452  try {
453  list.addAll(skCase.findAllFilesWhere(createBaseWhereExpr() + " AND mime_type = '" + mimeType + "'")
454  .stream().map(f -> new FileTypesKey(f)).collect(Collectors.toList())); //NON-NLS
455  } catch (TskCoreException ex) {
456  logger.log(Level.SEVERE, "Couldn't get search results", ex); //NON-NLS
457  }
458  return true;
459  }
460 
461  @Override
462  public void update(Observable o, Object arg) {
463  refresh(true);
464  }
465 
466  @Override
467  protected Node createNodeForKey(FileTypesKey key) {
468  return key.accept(new FileTypes.FileNodeCreationVisitor());
469  }
470  }
471 }
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 void removeEventTypeSubscriber(Set< Events > eventTypes, PropertyChangeListener subscriber)
Definition: Case.java:465

Copyright © 2012-2016 Basis Technology. Generated on: Mon May 7 2018
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.