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

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