Autopsy  4.1
Graphical digital forensics platform for The Sleuth Kit and other tools.
FilesSet.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2014 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.modules.interestingitems;
20 
21 import java.io.Serializable;
22 import java.util.ArrayList;
23 import java.util.HashMap;
24 import java.util.List;
25 import java.util.Map;
26 import java.util.UUID;
27 import java.util.regex.Pattern;
28 import org.sleuthkit.datamodel.AbstractFile;
29 import org.sleuthkit.datamodel.TskData;
30 
39 final class FilesSet implements Serializable {
40 
41  private static final long serialVersionUID = 1L;
42  private final String name;
43  private final String description;
44  private final boolean ignoreKnownFiles;
45  private final Map<String, Rule> rules = new HashMap<>();
46 
57  FilesSet(String name, String description, boolean ignoreKnownFiles, Map<String, Rule> rules) {
58  if ((name == null) || (name.isEmpty())) {
59  throw new IllegalArgumentException("Interesting files set name cannot be null or empty");
60  }
61  this.name = name;
62  this.description = (description != null ? description : "");
63  this.ignoreKnownFiles = ignoreKnownFiles;
64  if (rules != null) {
65  this.rules.putAll(rules);
66  }
67  }
68 
74  String getName() {
75  return this.name;
76  }
77 
83  String getDescription() {
84  return this.description;
85  }
86 
96  boolean ignoresKnownFiles() {
97  return this.ignoreKnownFiles;
98  }
99 
105  Map<String, Rule> getRules() {
106  return new HashMap<>(this.rules);
107  }
108 
117  String fileIsMemberOf(AbstractFile file) {
118  if ((this.ignoreKnownFiles) && (file.getKnown() == TskData.FileKnown.KNOWN)) {
119  return null;
120  }
121  for (Rule rule : rules.values()) {
122  if (rule.isSatisfied(file)) {
123  return rule.getName();
124  }
125  }
126  return null;
127  }
128 
129  @Override
130  public String toString() {
131  // This override is designed to provide a display name for use with
132  // javax.swing.DefaultListModel<E>.
133  return this.name;
134  }
135 
140  static class Rule implements Serializable {
141 
142  private static final long serialVersionUID = 1L;
143  private final String uuid;
144  private final String ruleName;
145  private final FileNameCondition fileNameCondition;
146  private final MetaTypeCondition metaTypeCondition;
147  private final ParentPathCondition pathCondition;
148  private final MimeTypeCondition mimeTypeCondition;
149  private final FileSizeCondition fileSizeCondition;
150  private final List<FileAttributeCondition> conditions = new ArrayList<>();
151 
162  Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition) {
163  // since ruleName is optional, ruleUUID can be used to uniquely identify a rule.
164  this.uuid = UUID.randomUUID().toString();
165  if (metaTypeCondition == null) {
166  throw new IllegalArgumentException("Interesting files set rule meta-type condition cannot be null");
167  }
168  if (pathCondition == null && fileNameCondition == null && mimeTypeCondition == null && fileSizeCondition == null) {
169  throw new IllegalArgumentException("Must have at least one condition on rule.");
170  }
171 
172  this.ruleName = ruleName;
173 
174  /*
175  * The rules are evaluated in the order added. MetaType check is
176  * fastest, so do it first
177  */
178  this.metaTypeCondition = metaTypeCondition;
179  this.conditions.add(this.metaTypeCondition);
180 
181  this.fileSizeCondition = fileSizeCondition;
182  if (this.fileSizeCondition != null) {
183  this.conditions.add(this.fileSizeCondition);
184  }
185 
186  this.fileNameCondition = fileNameCondition;
187  if (this.fileNameCondition != null) {
188  this.conditions.add(fileNameCondition);
189  }
190 
191  this.mimeTypeCondition = mimeTypeCondition;
192  if (this.mimeTypeCondition != null) {
193  this.conditions.add(mimeTypeCondition);
194  }
195 
196  this.pathCondition = pathCondition;
197  if (this.pathCondition != null) {
198  this.conditions.add(this.pathCondition);
199  }
200  }
201 
207  String getName() {
208  return ruleName;
209  }
210 
216  FileNameCondition getFileNameCondition() {
217  return this.fileNameCondition;
218  }
219 
225  MetaTypeCondition getMetaTypeCondition() {
226  return this.metaTypeCondition;
227  }
228 
234  ParentPathCondition getPathCondition() {
235  return this.pathCondition;
236  }
237 
245  boolean isSatisfied(AbstractFile file) {
246  for (FileAttributeCondition condition : conditions) {
247  if (!condition.passes(file)) {
248  return false;
249  }
250  }
251  return true;
252  }
253 
254  @Override
255  public String toString() {
256  // This override is designed to provide a display name for use with
257  // javax.swing.DefaultListModel<E>.
258  if (fileNameCondition != null) {
259  return this.ruleName + " (" + fileNameCondition.getTextToMatch() + ")";
260  } else if (this.pathCondition != null) {
261  return this.ruleName + " (" + pathCondition.getTextToMatch() + ")";
262  } else if (this.mimeTypeCondition != null) {
263  return this.ruleName + " (" + mimeTypeCondition.getMimeType() + ")";
264  } else if (this.fileSizeCondition != null) {
265  return this.ruleName + " (" + fileSizeCondition.getComparator().getSymbol() + " " + fileSizeCondition.getSizeValue()
266  + " " + fileSizeCondition.getUnit().getName() + ")";
267  } else {
268  return this.ruleName + " ()";
269  }
270 
271  }
272 
276  public String getUuid() {
277  return this.uuid;
278  }
279 
283  MimeTypeCondition getMimeTypeCondition() {
284  return mimeTypeCondition;
285  }
286 
290  FileSizeCondition getFileSizeCondition() {
291  return fileSizeCondition;
292  }
293 
298  static interface FileAttributeCondition extends Serializable {
299 
307  boolean passes(AbstractFile file);
308  }
309 
313  static final class MimeTypeCondition implements FileAttributeCondition {
314 
315  private static final long serialVersionUID = 1L;
316  private final String mimeType;
317 
323  MimeTypeCondition(String mimeType) {
324  this.mimeType = mimeType;
325  }
326 
327  @Override
328  public boolean passes(AbstractFile file) {
329  return this.mimeType.equals(file.getMIMEType());
330  }
331 
337  String getMimeType() {
338  return this.mimeType;
339  }
340 
341  }
342 
347  static final class FileSizeCondition implements FileAttributeCondition {
348 
349  private static final long serialVersionUID = 1L;
350 
354  static enum COMPARATOR {
355 
356  LESS_THAN("<"),
357  LESS_THAN_EQUAL("≤"),
358  EQUAL("="),
359  GREATER_THAN(">"),
360  GREATER_THAN_EQUAL("≥");
361 
362  private String symbol;
363 
364  COMPARATOR(String symbol) {
365  this.symbol = symbol;
366  }
367 
368  public static COMPARATOR fromSymbol(String symbol) {
369  if (symbol.equals("<=") || symbol.equals("≤")) {
370  return LESS_THAN_EQUAL;
371  } else if (symbol.equals("<")) {
372  return LESS_THAN;
373  } else if (symbol.equals("==") || symbol.equals("=")) {
374  return EQUAL;
375  } else if (symbol.equals(">")) {
376  return GREATER_THAN;
377  } else if (symbol.equals(">=") || symbol.equals("≥")) {
378  return GREATER_THAN_EQUAL;
379  } else {
380  throw new IllegalArgumentException("Invalid symbol");
381  }
382  }
383 
387  public String getSymbol() {
388  return symbol;
389  }
390  }
391 
395  static enum SIZE_UNIT {
396 
397  BYTE(1, "Bytes"),
398  KILOBYTE(1024, "Kilobytes"),
399  MEGABYTE(1024 * 1024, "Megabytes"),
400  GIGABYTE(1024 * 1024 * 1024, "Gigabytes");
401  private long size;
402  private String name;
403 
404  private SIZE_UNIT(long size, String name) {
405  this.size = size;
406  this.name = name;
407  }
408 
409  public long getSize() {
410  return this.size;
411  }
412 
413  public static SIZE_UNIT fromName(String name) {
414  for (SIZE_UNIT unit : SIZE_UNIT.values()) {
415  if (unit.getName().equals(name)) {
416  return unit;
417  }
418  }
419  throw new IllegalArgumentException("Invalid name for size unit.");
420  }
421 
425  public String getName() {
426  return name;
427  }
428  }
429  private final COMPARATOR comparator;
430  private final SIZE_UNIT unit;
431  private final int sizeValue;
432 
433  FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) {
434  this.comparator = comparator;
435  this.unit = unit;
436  this.sizeValue = sizeValue;
437  }
438 
444  COMPARATOR getComparator() {
445  return comparator;
446  }
447 
453  SIZE_UNIT getUnit() {
454  return unit;
455  }
456 
462  int getSizeValue() {
463  return sizeValue;
464  }
465 
466  @Override
467  public boolean passes(AbstractFile file) {
468  long fileSize = file.getSize();
469  long conditionSize = this.getUnit().getSize() * this.getSizeValue();
470  switch (this.getComparator()) {
471  case GREATER_THAN:
472  return fileSize > conditionSize;
473  case GREATER_THAN_EQUAL:
474  return fileSize >= conditionSize;
475  case LESS_THAN_EQUAL:
476  return fileSize <= conditionSize;
477  case LESS_THAN:
478  return fileSize < conditionSize;
479  default:
480  return fileSize == conditionSize;
481 
482  }
483  }
484 
485  }
486 
492  static final class MetaTypeCondition implements FileAttributeCondition {
493 
494  private static final long serialVersionUID = 1L;
495 
496  enum Type {
497 
498  FILES,
499  DIRECTORIES,
500  FILES_AND_DIRECTORIES
501  }
502 
503  private final Type type;
504 
510  MetaTypeCondition(Type type) {
511  this.type = type;
512  }
513 
514  @Override
515  public boolean passes(AbstractFile file) {
516  switch (this.type) {
517  case FILES:
518  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG;
519  case DIRECTORIES:
520  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
521  default:
522  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
523  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
524  }
525  }
526 
532  Type getMetaType() {
533  return this.type;
534  }
535  }
536 
540  static interface TextCondition extends FileAttributeCondition {
541 
547  String getTextToMatch();
548 
556  boolean isRegex();
557 
565  boolean textMatches(String textToMatch);
566 
567  }
568 
573  private static abstract class AbstractTextCondition implements TextCondition {
574 
575  private final TextMatcher textMatcher;
576 
582  AbstractTextCondition(String text, Boolean partialMatch) {
583  if (partialMatch) {
584  this.textMatcher = new FilesSet.Rule.CaseInsensitivePartialStringComparisionMatcher(text);
585  } else {
586  this.textMatcher = new FilesSet.Rule.CaseInsensitiveStringComparisionMatcher(text);
587  }
588  }
589 
595  AbstractTextCondition(Pattern regex) {
596  this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
597  }
598 
604  @Override
605  public String getTextToMatch() {
606  return this.textMatcher.getTextToMatch();
607  }
608 
616  @Override
617  public boolean isRegex() {
618  return this.textMatcher.isRegex();
619  }
620 
628  @Override
629  public boolean textMatches(String textToMatch) {
630  return this.textMatcher.textMatches(textToMatch);
631  }
632 
633  @Override
634  public abstract boolean passes(AbstractFile file);
635 
636  }
637 
643  static final class ParentPathCondition extends AbstractTextCondition {
644 
645  private static final long serialVersionUID = 1L;
646 
652  ParentPathCondition(String path) {
653  super(path, true);
654  }
655 
661  ParentPathCondition(Pattern path) {
662  super(path);
663  }
664 
665  @Override
666  public boolean passes(AbstractFile file) {
667  return this.textMatches(file.getParentPath() + "/");
668  }
669 
670  }
671 
677  static interface FileNameCondition extends TextCondition {
678  }
679 
685  static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition {
686 
687  private static final long serialVersionUID = 1L;
688 
694  FullNameCondition(String name) {
695  super(name, false);
696  }
697 
703  FullNameCondition(Pattern name) {
704  super(name);
705  }
706 
707  @Override
708  public boolean passes(AbstractFile file) {
709  return this.textMatches(file.getName());
710  }
711 
712  }
713 
719  static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition {
720 
721  private static final long serialVersionUID = 1L;
722 
728  ExtensionCondition(String extension) {
729  // If there is a leading ".", strip it since
730  // AbstractFile.getFileNameExtension() returns just the
731  // extension chars and not the dot.
732  super(extension.startsWith(".") ? extension.substring(1) : extension, false);
733  }
734 
741  ExtensionCondition(Pattern extension) {
742  super(extension.pattern(), false);
743  }
744 
745  @Override
746  public boolean passes(AbstractFile file) {
747  return this.textMatches(file.getNameExtension());
748  }
749 
750  }
751 
756  private static interface TextMatcher extends Serializable {
757 
763  String getTextToMatch();
764 
772  boolean isRegex();
773 
781  boolean textMatches(String subject);
782 
783  }
784 
788  private static class CaseInsensitiveStringComparisionMatcher implements TextMatcher {
789 
790  private static final long serialVersionUID = 1L;
791  private final String textToMatch;
792 
799  CaseInsensitiveStringComparisionMatcher(String textToMatch) {
800  this.textToMatch = textToMatch;
801  }
802 
803  @Override
804  public String getTextToMatch() {
805  return this.textToMatch;
806  }
807 
808  @Override
809  public boolean isRegex() {
810  return false;
811  }
812 
813  @Override
814  public boolean textMatches(String subject) {
815  return subject.equalsIgnoreCase(textToMatch);
816  }
817 
818  }
819 
824 
825  private static final long serialVersionUID = 1L;
826  private final String textToMatch;
827  private final Pattern pattern;
828 
836  this.textToMatch = textToMatch;
837  this.pattern = Pattern.compile(Pattern.quote(textToMatch), Pattern.CASE_INSENSITIVE);
838  }
839 
840  @Override
841  public String getTextToMatch() {
842  return this.textToMatch;
843  }
844 
845  @Override
846  public boolean isRegex() {
847  return false;
848  }
849 
850  @Override
851  public boolean textMatches(String subject) {
852  return pattern.matcher(subject).find();
853  }
854  }
855 
859  private static class RegexMatcher implements TextMatcher {
860 
861  private static final long serialVersionUID = 1L;
862  private final Pattern regex;
863 
870  RegexMatcher(Pattern regex) {
871  this.regex = regex;
872  }
873 
874  @Override
875  public String getTextToMatch() {
876  return this.regex.pattern();
877  }
878 
879  @Override
880  public boolean isRegex() {
881  return true;
882  }
883 
884  @Override
885  public boolean textMatches(String subject) {
886  // A single match is sufficient.
887  return this.regex.matcher(subject).find();
888  }
889 
890  }
891 
892  }
893 
894 }

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