Autopsy  4.19.3
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.Collections;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
27 import java.util.Map.Entry;
28 import java.util.UUID;
29 import java.util.regex.Pattern;
30 import org.openide.util.NbBundle;
31 import org.openide.util.NbBundle.Messages;
32 import org.sleuthkit.datamodel.AbstractFile;
33 import org.sleuthkit.datamodel.TskData;
34 
43 public final class FilesSet implements Serializable {
44 
45  private static final long serialVersionUID = 1L;
46  private final String name;
47  private final String description;
48  private final boolean ignoreKnownFiles;
49  private final boolean ignoreUnallocatedSpace;
50 
51  private final boolean standardSet;
52  private final int versionNumber;
53 
54  private final Map<String, Rule> rules;
55 
56  // NOTE: these fields are derived from 'rules' which may happen at runtime
57  // due to deserialization of older FilesSet objects before inclusive and
58  // exclusive rules existed.
59  private Map<String, Rule> inclusiveRules;
60  private Map<String, Rule> exclusiveRules;
61 
74  public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map<String, Rule> rules) {
76  }
77 
95  public FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map<String, Rule> rules,
96  boolean standardSet, int versionNumber) {
97  if ((name == null) || (name.isEmpty())) {
98  throw new IllegalArgumentException("Interesting files set name cannot be null or empty");
99  }
100 
101  if (versionNumber < 0) {
102  throw new IllegalArgumentException("version number must be >= 0");
103  }
104 
105  this.standardSet = standardSet;
106  this.versionNumber = versionNumber;
107 
108  this.name = name;
109  this.description = (description != null ? description : "");
110  this.ignoreKnownFiles = ignoreKnownFiles;
111  this.ignoreUnallocatedSpace = ignoreUnallocatedSpace;
112  this.rules = rules == null ? Collections.emptyMap() : new HashMap<>(rules);
113 
115  }
116 
120  private void divideInclusiveExclusive() {
121  Map<String, Rule> inclusiveRules = new HashMap<>();
122  Map<String, Rule> exclusiveRules = new HashMap<>();
123  if (this.rules != null) {
124  for (Entry<String, Rule> ruleEntry : this.rules.entrySet()) {
125  if (ruleEntry.getValue().isExclusive()) {
126  exclusiveRules.put(ruleEntry.getKey(), ruleEntry.getValue());
127  } else {
128  inclusiveRules.put(ruleEntry.getKey(), ruleEntry.getValue());
129  }
130  }
131  }
132  this.inclusiveRules = inclusiveRules;
133  this.exclusiveRules = exclusiveRules;
134  }
135 
140  boolean isStandardSet() {
141  return standardSet;
142  }
143 
148  int getVersionNumber() {
149  return versionNumber;
150  }
151 
157  public String getName() {
158  return this.name;
159  }
160 
166  public String getDescription() {
167  return this.description;
168  }
169 
179  public boolean ignoresKnownFiles() {
180  return this.ignoreKnownFiles;
181  }
182 
189  public boolean ingoresUnallocatedSpace() {
190  return this.ignoreUnallocatedSpace;
191  }
192 
198  public Map<String, Rule> getRules() {
199  return new HashMap<>(this.rules);
200  }
201 
202 
211  @Messages({
212  "FileSet_fileIsMemberOf_noInclusiveRules_ruleName=Not Excluded"
213  })
214  public String fileIsMemberOf(AbstractFile file) {
215  if ((this.ignoreKnownFiles) && (file.getKnown() == TskData.FileKnown.KNOWN)) {
216  return null;
217  }
218 
219  if ((this.ignoreUnallocatedSpace)
220  && (file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNALLOC_BLOCKS)
221  || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.SLACK)
222  || file.getType().equals(TskData.TSK_DB_FILES_TYPE_ENUM.UNUSED_BLOCKS))) {
223  return null;
224  }
225 
226  if (inclusiveRules == null || exclusiveRules == null) {
228  }
229 
230 
231  String ruleName;
232  if (inclusiveRules.isEmpty()) {
233  // in the event there are no rules, return null for no match
234  if (exclusiveRules.isEmpty()) {
235  return null;
236  // in the event there are exclusion rules, rely on those
237  } else {
238  ruleName = Bundle.FileSet_fileIsMemberOf_noInclusiveRules_ruleName();
239  }
240 
241  } else {
242  // if there are inclusive rules, at least one should be matched
243  ruleName = null;
244  for (Rule rule : inclusiveRules.values()) {
245  if (rule.isSatisfied(file)) {
246  ruleName = rule.getName();
247  break;
248  }
249  }
250  }
251 
252  for (Rule rule : exclusiveRules.values()) {
253  if (rule.isSatisfied(file)) {
254  return null;
255  }
256  }
257 
258  return ruleName;
259  }
260 
261  @Override
262  public String toString() {
263  // This override is designed to provide a display name for use with
264  // javax.swing.DefaultListModel<E>.
265  return this.name;
266  }
267 
272  public final static class Rule implements Serializable {
273 
274  private static final long serialVersionUID = 1L;
275  private final String uuid;
276  private final String ruleName;
277  private final Boolean exclusive;
278  private final FileNameCondition fileNameCondition;
284  private final List<FileAttributeCondition> conditions = new ArrayList<>();
285 
300  public Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition,
301  ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition,
302  FileSizeCondition fileSizeCondition, DateCondition dateCondition,
303  Boolean exclusive) {
304 
305  // since ruleName is optional, ruleUUID can be used to uniquely identify a rule.
306  this.uuid = UUID.randomUUID().toString();
307  if (metaTypeCondition == null) {
308  throw new IllegalArgumentException("Interesting files set rule meta-type condition cannot be null");
309  }
310 
311  this.ruleName = ruleName;
312 
313  /*
314  * The rules are evaluated in the order added. MetaType check is
315  * fastest, so do it first
316  */
317  this.metaTypeCondition = metaTypeCondition;
318  this.conditions.add(this.metaTypeCondition);
319 
320  this.fileSizeCondition = fileSizeCondition;
321  if (this.fileSizeCondition != null) {
322  this.conditions.add(this.fileSizeCondition);
323  }
324 
325  this.fileNameCondition = fileNameCondition;
326  if (this.fileNameCondition != null) {
327  this.conditions.add(fileNameCondition);
328  }
329 
330  this.mimeTypeCondition = mimeTypeCondition;
331  if (this.mimeTypeCondition != null) {
332  this.conditions.add(mimeTypeCondition);
333  }
334 
335  this.pathCondition = pathCondition;
336  if (this.pathCondition != null) {
337  this.conditions.add(this.pathCondition);
338  }
339  this.dateCondition = dateCondition;
340  if (this.dateCondition != null) {
341  this.conditions.add(this.dateCondition);
342  }
343 
344  this.exclusive = exclusive;
345  }
346 
352  public String getName() {
353  return ruleName;
354  }
355 
361  public FileNameCondition getFileNameCondition() {
362  return this.fileNameCondition;
363  }
364 
371  return this.metaTypeCondition;
372  }
373 
380  return this.pathCondition;
381  }
382 
384  return this.dateCondition;
385  }
386 
392  public boolean isExclusive() {
393  return exclusive != null && exclusive == true;
394  }
395 
403  public boolean isSatisfied(AbstractFile file) {
404  for (FileAttributeCondition condition : conditions) {
405  if (!condition.passes(file)) {
406  return false;
407  }
408  }
409  return true;
410  }
411 
412  @NbBundle.Messages({
413  "# {0} - daysIncluded",
414  "FilesSet.rule.dateRule.toString=(modified within {0} day(s))"
415  })
416  @Override
417  public String toString() {
418  // This override is designed to provide a display name for use with
419  // javax.swing.DefaultListModel<E>.
420  if (fileNameCondition != null) {
421  return this.ruleName + " (" + fileNameCondition.getTextToMatch() + ")";
422  } else if (this.pathCondition != null) {
423  return this.ruleName + " (" + pathCondition.getTextToMatch() + ")";
424  } else if (this.mimeTypeCondition != null) {
425  return this.ruleName + " (" + mimeTypeCondition.getMimeType() + ")";
426  } else if (this.fileSizeCondition != null) {
427  return this.ruleName + " (" + fileSizeCondition.getComparator().getSymbol() + " " + fileSizeCondition.getSizeValue()
428  + " " + fileSizeCondition.getUnit().getName() + ")";
429  } else if (this.dateCondition != null) {
430  return this.ruleName + Bundle.FilesSet_rule_dateRule_toString(dateCondition.getDaysIncluded());
431  } else {
432  return this.ruleName + " ()";
433  }
434 
435  }
436 
440  public String getUuid() {
441  return this.uuid;
442  }
443 
448  return mimeTypeCondition;
449  }
450 
455  return fileSizeCondition;
456  }
457 
462  static interface FileAttributeCondition extends Serializable {
463 
471  boolean passes(AbstractFile file);
472  }
473 
477  public static final class MimeTypeCondition implements FileAttributeCondition {
478 
479  private static final long serialVersionUID = 1L;
480  private final String mimeType;
481 
487  public MimeTypeCondition(String mimeType) {
488  this.mimeType = mimeType;
489  }
490 
491  @Override
492  public boolean passes(AbstractFile file) {
493  return this.mimeType.equals(file.getMIMEType());
494  }
495 
501  public String getMimeType() {
502  return this.mimeType;
503  }
504 
505  }
506 
511  public static final class FileSizeCondition implements FileAttributeCondition {
512 
513  private static final long serialVersionUID = 1L;
514 
518  public static enum COMPARATOR {
519 
520  LESS_THAN("<"),
521  LESS_THAN_EQUAL("≤"),
522  EQUAL("="),
524  GREATER_THAN_EQUAL("≥");
525 
526  private String symbol;
527 
528  private COMPARATOR(String symbol) {
529  this.symbol = symbol;
530  }
531 
532  public static COMPARATOR fromSymbol(String symbol) {
533  switch (symbol) {
534  case "<=":
535  case "≤":
536  return LESS_THAN_EQUAL;
537  case "<":
538  return LESS_THAN;
539  case "==":
540  case "=":
541  return EQUAL;
542  case ">":
543  return GREATER_THAN;
544  case ">=":
545  case "≥":
546  return GREATER_THAN_EQUAL;
547  default:
548  throw new IllegalArgumentException("Invalid symbol");
549  }
550  }
551 
555  public String getSymbol() {
556  return symbol;
557  }
558  }
559 
563  public static enum SIZE_UNIT {
564 
565  BYTE(1, "Bytes"),
566  KILOBYTE(1024, "Kilobytes"),
567  MEGABYTE(1024 * 1024, "Megabytes"),
568  GIGABYTE(1024 * 1024 * 1024, "Gigabytes");
569  private long size;
570  private String name;
571 
572  private SIZE_UNIT(long size, String name) {
573  this.size = size;
574  this.name = name;
575  }
576 
577  public long getSize() {
578  return this.size;
579  }
580 
581  public static SIZE_UNIT fromName(String name) {
582  for (SIZE_UNIT unit : SIZE_UNIT.values()) {
583  if (unit.getName().equals(name)) {
584  return unit;
585  }
586  }
587  throw new IllegalArgumentException("Invalid name for size unit.");
588  }
589 
593  public String getName() {
594  return name;
595  }
596  }
597  private final COMPARATOR comparator;
598  private final SIZE_UNIT unit;
599  private final int sizeValue;
600 
601  public FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) {
602  this.comparator = comparator;
603  this.unit = unit;
604  this.sizeValue = sizeValue;
605  }
606 
613  return comparator;
614  }
615 
621  public SIZE_UNIT getUnit() {
622  return unit;
623  }
624 
630  public int getSizeValue() {
631  return sizeValue;
632  }
633 
634  @Override
635  public boolean passes(AbstractFile file) {
636  long fileSize = file.getSize();
637  long conditionSize = this.getUnit().getSize() * this.getSizeValue();
638  switch (this.getComparator()) {
639  case GREATER_THAN:
640  return fileSize > conditionSize;
641  case GREATER_THAN_EQUAL:
642  return fileSize >= conditionSize;
643  case LESS_THAN_EQUAL:
644  return fileSize <= conditionSize;
645  case LESS_THAN:
646  return fileSize < conditionSize;
647  default:
648  return fileSize == conditionSize;
649 
650  }
651  }
652 
653  }
654 
660  public static final class MetaTypeCondition implements FileAttributeCondition {
661 
662  private static final long serialVersionUID = 1L;
663 
664  public enum Type {
665 
669  ALL
670  }
671 
672  private final Type type;
673 
679  public MetaTypeCondition(Type type) {
680  this.type = type;
681  }
682 
683  @Override
684  public boolean passes(AbstractFile file) {
685  switch (this.type) {
686  case FILES:
687  return file.isFile();
688  case DIRECTORIES:
689  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
690  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
691  case FILES_AND_DIRECTORIES:
692  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
693  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR
694  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_VIRT_DIR;
695  case ALL:
696  return true; //Effectively ignores the metatype condition when All is selected.
697  default:
698  return true;
699  }
700  }
701 
707  public Type getMetaType() {
708  return this.type;
709  }
710  }
711 
715  static interface TextCondition extends FileAttributeCondition {
716 
722  String getTextToMatch();
723 
731  boolean isRegex();
732 
740  boolean textMatches(String textToMatch);
741 
742  }
743 
748  private static abstract class AbstractTextCondition implements TextCondition {
749 
750  /*
751  * To ensure compatibility with existing serialized configuration
752  * settings, this class cannot have a 'serialVersionUID'.
753  */
754  private final TextMatcher textMatcher;
755 
761  AbstractTextCondition(String text, Boolean partialMatch) {
762  if (partialMatch) {
763  this.textMatcher = new FilesSet.Rule.CaseInsensitivePartialStringComparisionMatcher(text);
764  } else {
765  this.textMatcher = new FilesSet.Rule.CaseInsensitiveStringComparisionMatcher(text);
766  }
767  }
768 
774  AbstractTextCondition(Pattern regex) {
775  this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
776  }
777 
783  AbstractTextCondition(List<String> values) {
784  this.textMatcher = new FilesSet.Rule.CaseInsensitiveMultiValueStringComparisionMatcher(values);
785  }
786 
792  @Override
793  public String getTextToMatch() {
794  return this.textMatcher.getTextToMatch();
795  }
796 
804  @Override
805  public boolean isRegex() {
806  return this.textMatcher.isRegex();
807  }
808 
816  @Override
817  public boolean textMatches(String textToMatch) {
818  return this.textMatcher.textMatches(textToMatch);
819  }
820 
821  @Override
822  public abstract boolean passes(AbstractFile file);
823 
824  }
825 
831  public static final class ParentPathCondition extends AbstractTextCondition {
832 
833  private static final long serialVersionUID = 1L;
834 
840  public ParentPathCondition(String path) {
841  super(path, true);
842  }
843 
849  public ParentPathCondition(Pattern path) {
850  super(path);
851  }
852 
853  @Override
854  public boolean passes(AbstractFile file) {
855  return this.textMatches(file.getParentPath() + "/");
856  }
857 
858  }
859 
865  static interface FileNameCondition extends TextCondition {
866  }
867 
873  public static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition {
874 
875  private static final long serialVersionUID = 1L;
876 
882  public FullNameCondition(String name) {
883  super(name, false);
884  }
885 
891  public FullNameCondition(Pattern name) {
892  super(name);
893  }
894 
895  @Override
896  public boolean passes(AbstractFile file) {
897  return this.textMatches(file.getName());
898  }
899 
900  }
901 
906  public static final class DateCondition implements FileAttributeCondition {
907 
908  /*
909  * To ensure compatibility with existing serialized configuration
910  * settings, this class cannot have a 'serialVersionUID'.
911  */
912  private final static long SECS_PER_DAY = 60 * 60 * 24;
913 
914  private int daysIncluded;
915 
922  public DateCondition(int days) {
923  daysIncluded = days;
924  }
925 
931  public int getDaysIncluded() {
932  return daysIncluded;
933  }
934 
935  @Override
936  public boolean passes(AbstractFile file) {
937  long dateThreshold = System.currentTimeMillis() / 1000 - daysIncluded * SECS_PER_DAY;
938  return file.getCrtime() > dateThreshold || file.getMtime() > dateThreshold;
939  }
940 
941  }
942 
948  public static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition {
949 
950  private static final long serialVersionUID = 1L;
951 
957  public ExtensionCondition(String extension) {
958  // If there is a leading ".", strip it since
959  // AbstractFile.getFileNameExtension() returns just the
960  // extension chars and not the dot.
961  super(normalize(extension), false);
962  }
963 
969  public ExtensionCondition(List<String> extensions) {
970  // If there is a leading "." in any list value, strip it since
971  // AbstractFile.getFileNameExtension() returns just the
972  // extension chars and not the dot.
973  super(normalize(extensions));
974  }
975 
982  public ExtensionCondition(Pattern extension) {
983  super(extension);
984  }
985 
986  @Override
987  public boolean passes(AbstractFile file) {
988  return this.textMatches(file.getNameExtension());
989  }
990 
998  private static List<String> normalize(List<String> extensions) {
999  List<String> values = new ArrayList<>(extensions);
1000 
1001  for (int i = 0; i < values.size(); i++) {
1002  values.set(i, normalize(values.get(i)));
1003  }
1004 
1005  return values;
1006  }
1007 
1015  private static String normalize(String extension) {
1016  return extension.startsWith(".") ? extension.substring(1) : extension;
1017  }
1018 
1019  }
1020 
1025  private static interface TextMatcher extends Serializable {
1026 
1032  String getTextToMatch();
1033 
1041  boolean isRegex();
1042 
1050  boolean textMatches(String subject);
1051 
1052  }
1053 
1057  private static class CaseInsensitiveStringComparisionMatcher implements TextMatcher {
1058 
1059  private static final long serialVersionUID = 1L;
1060  private final String textToMatch;
1061 
1068  CaseInsensitiveStringComparisionMatcher(String textToMatch) {
1069  this.textToMatch = textToMatch;
1070  }
1071 
1072  @Override
1073  public String getTextToMatch() {
1074  return this.textToMatch;
1075  }
1076 
1077  @Override
1078  public boolean isRegex() {
1079  return false;
1080  }
1081 
1082  @Override
1083  public boolean textMatches(String subject) {
1084  return subject.equalsIgnoreCase(textToMatch);
1085  }
1086 
1087  }
1088 
1093 
1094  private static final long serialVersionUID = 1L;
1095  private final String textToMatch;
1096  private final Pattern pattern;
1097 
1105  this.textToMatch = textToMatch;
1106  this.pattern = Pattern.compile(Pattern.quote(textToMatch), Pattern.CASE_INSENSITIVE);
1107  }
1108 
1109  @Override
1110  public String getTextToMatch() {
1111  return this.textToMatch;
1112  }
1113 
1114  @Override
1115  public boolean isRegex() {
1116  return false;
1117  }
1118 
1119  @Override
1120  public boolean textMatches(String subject) {
1121  return pattern.matcher(subject).find();
1122  }
1123  }
1124 
1130 
1131  private static final long serialVersionUID = 1L;
1132  private final List<String> valuesToMatch;
1133 
1141  CaseInsensitiveMultiValueStringComparisionMatcher(List<String> valuesToMatch) {
1142  this.valuesToMatch = valuesToMatch;
1143  }
1144 
1145  @Override
1146  public String getTextToMatch() {
1147  return String.join(",", this.valuesToMatch);
1148  }
1149 
1150  @Override
1151  public boolean isRegex() {
1152  return false;
1153  }
1154 
1155  @Override
1156  public boolean textMatches(String subject) {
1157  for (String value : valuesToMatch) {
1158  if (value.equalsIgnoreCase(subject)) {
1159  return true;
1160  }
1161  }
1162  return false;
1163  }
1164 
1165  }
1166 
1170  private static class RegexMatcher implements TextMatcher {
1171 
1172  private static final long serialVersionUID = 1L;
1173  private final Pattern regex;
1174 
1181  RegexMatcher(Pattern regex) {
1182  this.regex = regex;
1183  }
1184 
1185  @Override
1186  public String getTextToMatch() {
1187  return this.regex.pattern();
1188  }
1189 
1190  @Override
1191  public boolean isRegex() {
1192  return true;
1193  }
1194 
1195  @Override
1196  public boolean textMatches(String subject) {
1197  // A single match is sufficient.
1198  return this.regex.matcher(subject).find();
1199  }
1200 
1201  }
1202 
1203  }
1204 
1205 }
FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue)
Definition: FilesSet.java:601
FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map< String, Rule > rules)
Definition: FilesSet.java:74
FilesSet(String name, String description, boolean ignoreKnownFiles, boolean ignoreUnallocatedSpace, Map< String, Rule > rules, boolean standardSet, int versionNumber)
Definition: FilesSet.java:95
Rule(String ruleName, FileNameCondition fileNameCondition, MetaTypeCondition metaTypeCondition, ParentPathCondition pathCondition, MimeTypeCondition mimeTypeCondition, FileSizeCondition fileSizeCondition, DateCondition dateCondition, Boolean exclusive)
Definition: FilesSet.java:300
final List< FileAttributeCondition > conditions
Definition: FilesSet.java:284

Copyright © 2012-2022 Basis Technology. Generated on: Tue Jun 27 2023
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.