Autopsy  4.10.0
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 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.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.openide.util.NbBundle;
29 import org.sleuthkit.datamodel.AbstractFile;
30 import org.sleuthkit.datamodel.TskData;
31 
40 public final class FilesSet implements Serializable {
41 
42  private static final long serialVersionUID = 1L;
43  private final String name;
44  private final String description;
45  private final boolean ignoreKnownFiles;
46  private final boolean ignoreUnallocatedSpace;
47  private final Map<String, Rule> rules = new HashMap<>();
48 
61  public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map<String, Rule> rules) {
62  if ((name == null) || (name.isEmpty())) {
63  throw new IllegalArgumentException("Interesting files set name cannot be null or empty");
64  }
65  this.name = name;
66  this.description = (description != null ? description : "");
67  this.ignoreKnownFiles = ignoreKnownFiles;
68  this.ignoreUnallocatedSpace = ignoreUnallocatedSpace;
69  if (rules != null) {
70  this.rules.putAll(rules);
71  }
72  }
73 
79  public String getName() {
80  return this.name;
81  }
82 
88  public String getDescription() {
89  return this.description;
90  }
91 
101  public boolean ignoresKnownFiles() {
102  return this.ignoreKnownFiles;
103  }
104 
111  public boolean ingoresUnallocatedSpace() {
112  return this.ignoreUnallocatedSpace;
113  }
114 
120  public Map<String, Rule> getRules() {
121  return new HashMap<>(this.rules);
122  }
123 
132  public String fileIsMemberOf(AbstractFile file) {
133  if ((this.ignoreKnownFiles) && (file.getKnown() == TskData.FileKnown.KNOWN)) {
134  return null;
135  }
136 
137  if ((this.ignoreUnallocatedSpace)
138  && (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
139  || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
140  || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))) {
141  return null;
142  }
143 
144  for (Rule rule : rules.values()) {
145  if (rule.isSatisfied(file)) {
146  return rule.getName();
147  }
148  }
149  return null;
150  }
151 
152  @Override
153  public String toString() {
154  // This override is designed to provide a display name for use with
155  // javax.swing.DefaultListModel<E>.
156  return this.name;
157  }
158 
163  public final static class Rule implements Serializable {
164 
165  private static final long serialVersionUID = 1L;
166  private final String uuid;
167  private final String ruleName;
168  private final FileNameCondition fileNameCondition;
174  private final List<FileAttributeCondition> conditions = new ArrayList<>();
175 
188  public Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition, DateCondition dateCondition) {
189  // since ruleName is optional, ruleUUID can be used to uniquely identify a rule.
190  this.uuid = UUID.randomUUID().toString();
191  if (metaTypeCondition == null) {
192  throw new IllegalArgumentException("Interesting files set rule meta-type condition cannot be null");
193  }
194 
195  this.ruleName = ruleName;
196 
197  /*
198  * The rules are evaluated in the order added. MetaType check is
199  * fastest, so do it first
200  */
201  this.metaTypeCondition = metaTypeCondition;
202  this.conditions.add(this.metaTypeCondition);
203 
204  this.fileSizeCondition = fileSizeCondition;
205  if (this.fileSizeCondition != null) {
206  this.conditions.add(this.fileSizeCondition);
207  }
208 
209  this.fileNameCondition = fileNameCondition;
210  if (this.fileNameCondition != null) {
211  this.conditions.add(fileNameCondition);
212  }
213 
214  this.mimeTypeCondition = mimeTypeCondition;
215  if (this.mimeTypeCondition != null) {
216  this.conditions.add(mimeTypeCondition);
217  }
218 
219  this.pathCondition = pathCondition;
220  if (this.pathCondition != null) {
221  this.conditions.add(this.pathCondition);
222  }
223  this.dateCondition = dateCondition;
224  if (this.dateCondition != null) {
225  this.conditions.add(this.dateCondition);
226  }
227  }
228 
234  public String getName() {
235  return ruleName;
236  }
237 
243  public FileNameCondition getFileNameCondition() {
244  return this.fileNameCondition;
245  }
246 
253  return this.metaTypeCondition;
254  }
255 
262  return this.pathCondition;
263  }
264 
266  return this.dateCondition;
267  }
268 
276  public boolean isSatisfied(AbstractFile file) {
277  for (FileAttributeCondition condition : conditions) {
278  if (!condition.passes(file)) {
279  return false;
280  }
281  }
282  return true;
283  }
284 
285  @NbBundle.Messages({
286  "# {0} - daysIncluded",
287  "FilesSet.rule.dateRule.toString=(modified within {0} day(s))"
288  })
289  @Override
290  public String toString() {
291  // This override is designed to provide a display name for use with
292  // javax.swing.DefaultListModel<E>.
293  if (fileNameCondition != null) {
294  return this.ruleName + " (" + fileNameCondition.getTextToMatch() + ")";
295  } else if (this.pathCondition != null) {
296  return this.ruleName + " (" + pathCondition.getTextToMatch() + ")";
297  } else if (this.mimeTypeCondition != null) {
298  return this.ruleName + " (" + mimeTypeCondition.getMimeType() + ")";
299  } else if (this.fileSizeCondition != null) {
300  return this.ruleName + " (" + fileSizeCondition.getComparator().getSymbol() + " " + fileSizeCondition.getSizeValue()
301  + " " + fileSizeCondition.getUnit().getName() + ")";
302  } else if (this.dateCondition != null) {
303  return this.ruleName + Bundle.FilesSet_rule_dateRule_toString(dateCondition.getDaysIncluded());
304  } else {
305  return this.ruleName + " ()";
306  }
307 
308  }
309 
313  public String getUuid() {
314  return this.uuid;
315  }
316 
321  return mimeTypeCondition;
322  }
323 
328  return fileSizeCondition;
329  }
330 
335  static interface FileAttributeCondition extends Serializable {
336 
344  boolean passes(AbstractFile file);
345  }
346 
350  public static final class MimeTypeCondition implements FileAttributeCondition {
351 
352  private static final long serialVersionUID = 1L;
353  private final String mimeType;
354 
360  public MimeTypeCondition(String mimeType) {
361  this.mimeType = mimeType;
362  }
363 
364  @Override
365  public boolean passes(AbstractFile file) {
366  return this.mimeType.equals(file.getMIMEType());
367  }
368 
374  public String getMimeType() {
375  return this.mimeType;
376  }
377 
378  }
379 
384  public static final class FileSizeCondition implements FileAttributeCondition {
385 
386  private static final long serialVersionUID = 1L;
387 
391  public static enum COMPARATOR {
392 
393  LESS_THAN("<"),
395  EQUAL("="),
398 
399  private String symbol;
400 
401  private COMPARATOR(String symbol) {
402  this.symbol = symbol;
403  }
404 
405  public static COMPARATOR fromSymbol(String symbol) {
406  switch (symbol) {
407  case "<=":
408  case "≤":
409  return LESS_THAN_EQUAL;
410  case "<":
411  return LESS_THAN;
412  case "==":
413  case "=":
414  return EQUAL;
415  case ">":
416  return GREATER_THAN;
417  case ">=":
418  case "≥":
419  return GREATER_THAN_EQUAL;
420  default:
421  throw new IllegalArgumentException("Invalid symbol");
422  }
423  }
424 
428  public String getSymbol() {
429  return symbol;
430  }
431  }
432 
436  public static enum SIZE_UNIT {
437 
438  BYTE(1, "Bytes"),
439  KILOBYTE(1024, "Kilobytes"),
440  MEGABYTE(1024 * 1024, "Megabytes"),
441  GIGABYTE(1024 * 1024 * 1024, "Gigabytes");
442  private long size;
443  private String name;
444 
445  private SIZE_UNIT(long size, String name) {
446  this.size = size;
447  this.name = name;
448  }
449 
450  public long getSize() {
451  return this.size;
452  }
453 
454  public static SIZE_UNIT fromName(String name) {
455  for (SIZE_UNIT unit : SIZE_UNIT.values()) {
456  if (unit.getName().equals(name)) {
457  return unit;
458  }
459  }
460  throw new IllegalArgumentException("Invalid name for size unit.");
461  }
462 
466  public String getName() {
467  return name;
468  }
469  }
470  private final COMPARATOR comparator;
471  private final SIZE_UNIT unit;
472  private final int sizeValue;
473 
474  public FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) {
475  this.comparator = comparator;
476  this.unit = unit;
477  this.sizeValue = sizeValue;
478  }
479 
486  return comparator;
487  }
488 
494  public SIZE_UNIT getUnit() {
495  return unit;
496  }
497 
503  public int getSizeValue() {
504  return sizeValue;
505  }
506 
507  @Override
508  public boolean passes(AbstractFile file) {
509  long fileSize = file.getSize();
510  long conditionSize = this.getUnit().getSize() * this.getSizeValue();
511  switch (this.getComparator()) {
512  case GREATER_THAN:
513  return fileSize > conditionSize;
514  case GREATER_THAN_EQUAL:
515  return fileSize >= conditionSize;
516  case LESS_THAN_EQUAL:
517  return fileSize <= conditionSize;
518  case LESS_THAN:
519  return fileSize < conditionSize;
520  default:
521  return fileSize == conditionSize;
522 
523  }
524  }
525 
526  }
527 
533  public static final class MetaTypeCondition implements FileAttributeCondition {
534 
535  private static final long serialVersionUID = 1L;
536 
537  public enum Type {
538 
542  ALL
543  }
544 
545  private final Type type;
546 
552  public MetaTypeCondition(Type type) {
553  this.type = type;
554  }
555 
556  @Override
557  public boolean passes(AbstractFile file) {
558  switch (this.type) {
559  case FILES:
560  return file.isFile();
561  case DIRECTORIES:
562  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
563  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
564  case FILES_AND_DIRECTORIES:
565  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
566  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
567  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
568  case ALL:
569  return true; //Effectively ignores the metatype condition when All is selected.
570  default:
571  return true;
572  }
573  }
574 
580  public Type getMetaType() {
581  return this.type;
582  }
583  }
584 
588  static interface TextCondition extends FileAttributeCondition {
589 
595  String getTextToMatch();
596 
604  boolean isRegex();
605 
613  boolean textMatches(String textToMatch);
614 
615  }
616 
621  private static abstract class AbstractTextCondition implements TextCondition {
622 
623  /*
624  * To ensure compatibility with existing serialized configuration
625  * settings, this class cannot have a 'serialVersionUID'.
626  */
627 
628  private final TextMatcher textMatcher;
629 
635  AbstractTextCondition(String text, Boolean partialMatch) {
636  if (partialMatch) {
637  this.textMatcher = new FilesSet.Rule.CaseInsensitivePartialStringComparisionMatcher(text);
638  } else {
639  this.textMatcher = new FilesSet.Rule.CaseInsensitiveStringComparisionMatcher(text);
640  }
641  }
642 
648  AbstractTextCondition(Pattern regex) {
649  this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
650  }
651 
657  AbstractTextCondition(List<String> values) {
658  this.textMatcher = new FilesSet.Rule.CaseInsensitiveMultiValueStringComparisionMatcher(values);
659  }
660 
666  @Override
667  public String getTextToMatch() {
668  return this.textMatcher.getTextToMatch();
669  }
670 
678  @Override
679  public boolean isRegex() {
680  return this.textMatcher.isRegex();
681  }
682 
690  @Override
691  public boolean textMatches(String textToMatch) {
692  return this.textMatcher.textMatches(textToMatch);
693  }
694 
695  @Override
696  public abstract boolean passes(AbstractFile file);
697 
698  }
699 
705  public static final class ParentPathCondition extends AbstractTextCondition {
706 
707  private static final long serialVersionUID = 1L;
708 
714  public ParentPathCondition(String path) {
715  super(path, true);
716  }
717 
723  public ParentPathCondition(Pattern path) {
724  super(path);
725  }
726 
727  @Override
728  public boolean passes(AbstractFile file) {
729  return this.textMatches(file.getParentPath() + "/");
730  }
731 
732  }
733 
739  static interface FileNameCondition extends TextCondition {
740  }
741 
747  public static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition {
748 
749  private static final long serialVersionUID = 1L;
750 
756  public FullNameCondition(String name) {
757  super(name, false);
758  }
759 
765  public FullNameCondition(Pattern name) {
766  super(name);
767  }
768 
769  @Override
770  public boolean passes(AbstractFile file) {
771  return this.textMatches(file.getName());
772  }
773 
774  }
775 
780  public static final class DateCondition implements FileAttributeCondition {
781 
782  /*
783  * To ensure compatibility with existing serialized configuration
784  * settings, this class cannot have a 'serialVersionUID'.
785  */
786 
787  private final static long SECS_PER_DAY = 60 * 60 * 24;
788 
789  private int daysIncluded;
790 
797  public DateCondition(int days) {
798  daysIncluded = days;
799  }
800 
806  public int getDaysIncluded() {
807  return daysIncluded;
808  }
809 
810  @Override
811  public boolean passes(AbstractFile file) {
812  long dateThreshold = System.currentTimeMillis() / 1000 - daysIncluded * SECS_PER_DAY;
813  return file.getCrtime() > dateThreshold || file.getMtime() > dateThreshold;
814  }
815 
816  }
817 
823  public static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition {
824 
825  private static final long serialVersionUID = 1L;
826 
832  public ExtensionCondition(String extension) {
833  // If there is a leading ".", strip it since
834  // AbstractFile.getFileNameExtension() returns just the
835  // extension chars and not the dot.
836  super(normalize(extension), false);
837  }
838 
844  public ExtensionCondition(List<String> extensions) {
845  // If there is a leading "." in any list value, strip it since
846  // AbstractFile.getFileNameExtension() returns just the
847  // extension chars and not the dot.
848  super(normalize(extensions));
849  }
850 
857  public ExtensionCondition(Pattern extension) {
858  super(extension);
859  }
860 
861  @Override
862  public boolean passes(AbstractFile file) {
863  return this.textMatches(file.getNameExtension());
864  }
865 
873  private static List<String> normalize(List<String> extensions) {
874  List<String> values = new ArrayList<>(extensions);
875 
876  for (int i=0; i < values.size(); i++) {
877  values.set(i, normalize(values.get(i)));
878  }
879 
880  return values;
881  }
882 
890  private static String normalize(String extension) {
891  return extension.startsWith(".") ? extension.substring(1) : extension;
892  }
893 
894  }
895 
900  private static interface TextMatcher extends Serializable {
901 
907  String getTextToMatch();
908 
916  boolean isRegex();
917 
925  boolean textMatches(String subject);
926 
927  }
928 
932  private static class CaseInsensitiveStringComparisionMatcher implements TextMatcher {
933 
934  private static final long serialVersionUID = 1L;
935  private final String textToMatch;
936 
943  CaseInsensitiveStringComparisionMatcher(String textToMatch) {
944  this.textToMatch = textToMatch;
945  }
946 
947  @Override
948  public String getTextToMatch() {
949  return this.textToMatch;
950  }
951 
952  @Override
953  public boolean isRegex() {
954  return false;
955  }
956 
957  @Override
958  public boolean textMatches(String subject) {
959  return subject.equalsIgnoreCase(textToMatch);
960  }
961 
962  }
963 
968 
969  private static final long serialVersionUID = 1L;
970  private final String textToMatch;
971  private final Pattern pattern;
972 
980  this.textToMatch = textToMatch;
981  this.pattern = Pattern.compile(Pattern.quote(textToMatch), Pattern.CASE_INSENSITIVE);
982  }
983 
984  @Override
985  public String getTextToMatch() {
986  return this.textToMatch;
987  }
988 
989  @Override
990  public boolean isRegex() {
991  return false;
992  }
993 
994  @Override
995  public boolean textMatches(String subject) {
996  return pattern.matcher(subject).find();
997  }
998  }
999 
1005 
1006  private static final long serialVersionUID = 1L;
1007  private final List<String> valuesToMatch;
1008 
1016  CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
1017  this.valuesToMatch = valuesToMatch;
1018  }
1019 
1020  @Override
1021  public String getTextToMatch() {
1022  return String.join(",", this.valuesToMatch);
1023  }
1024 
1025  @Override
1026  public boolean isRegex() {
1027  return false;
1028  }
1029 
1030  @Override
1031  public boolean textMatches(String subject) {
1032  for (String value : valuesToMatch) {
1033  if (value.equalsIgnoreCase(subject)) {
1034  return true;
1035  }
1036  }
1037  return false;
1038  }
1039 
1040  }
1041 
1045  private static class RegexMatcher implements TextMatcher {
1046 
1047  private static final long serialVersionUID = 1L;
1048  private final Pattern regex;
1049 
1056  RegexMatcher(Pattern regex) {
1057  this.regex = regex;
1058  }
1059 
1060  @Override
1061  public String getTextToMatch() {
1062  return this.regex.pattern();
1063  }
1064 
1065  @Override
1066  public boolean isRegex() {
1067  return true;
1068  }
1069 
1070  @Override
1071  public boolean textMatches(String subject) {
1072  // A single match is sufficient.
1073  return this.regex.matcher(subject).find();
1074  }
1075 
1076  }
1077 
1078  }
1079 
1080 }
FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue)
Definition: FilesSet.java:474
FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map< String, Rule > rules)
Definition: FilesSet.java:61
Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition, DateCondition dateCondition)
Definition: FilesSet.java:188
final List< FileAttributeCondition > conditions
Definition: FilesSet.java:174

Copyright © 2012-2018 Basis Technology. Generated on: Fri Mar 22 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.