Autopsy  4.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 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 
257  @Override
258  public String toString() {
259  // This override is designed to provide a display name for use with
260  // javax.swing.DefaultListModel<E>.
261  if (fileNameCondition != null) {
262  return this.ruleName + " (" + fileNameCondition.getTextToMatch() + ")";
263  } else if (this.pathCondition != null) {
264  return this.ruleName + " (" + pathCondition.getTextToMatch() + ")";
265  } else if (this.mimeTypeCondition != null) {
266  return this.ruleName + " (" + mimeTypeCondition.getMimeType() + ")";
267  } else if (this.fileSizeCondition != null) {
268  return this.ruleName + " (" + fileSizeCondition.getComparator().getSymbol() + " " + fileSizeCondition.getSizeValue()
269  + " " + fileSizeCondition.getUnit().getName() + ")";
270  } else {
271  return this.ruleName + " ()";
272  }
273 
274  }
275 
279  public String getUuid() {
280  return this.uuid;
281  }
282 
286  MimeTypeCondition getMimeTypeCondition() {
287  return mimeTypeCondition;
288  }
289 
293  FileSizeCondition getFileSizeCondition() {
294  return fileSizeCondition;
295  }
296 
301  static interface FileAttributeCondition extends Serializable {
302 
310  boolean passes(AbstractFile file);
311  }
312 
316  static final class MimeTypeCondition implements FileAttributeCondition {
317 
318  private static final long serialVersionUID = 1L;
319  private final String mimeType;
320 
326  MimeTypeCondition(String mimeType) {
327  this.mimeType = mimeType;
328  }
329 
333  @Override
334  public boolean passes(AbstractFile file) {
335  return this.mimeType.equals(file.getMIMEType());
336  }
337 
343  String getMimeType() {
344  return this.mimeType;
345  }
346 
347  }
348 
353  static final class FileSizeCondition implements FileAttributeCondition {
354 
355  private static final long serialVersionUID = 1L;
356 
360  static enum COMPARATOR {
361 
362  LESS_THAN("<"),
363  LESS_THAN_EQUAL("≤"),
364  EQUAL("="),
365  GREATER_THAN(">"),
366  GREATER_THAN_EQUAL("≥");
367 
368  private String symbol;
369 
370  COMPARATOR(String symbol) {
371  this.symbol = symbol;
372  }
373 
374  public static COMPARATOR fromSymbol(String symbol) {
375  if (symbol.equals("<=") || symbol.equals("≤")) {
376  return LESS_THAN_EQUAL;
377  } else if (symbol.equals("<")) {
378  return LESS_THAN;
379  } else if (symbol.equals("==") || symbol.equals("=")) {
380  return EQUAL;
381  } else if (symbol.equals(">")) {
382  return GREATER_THAN;
383  } else if (symbol.equals(">=") || symbol.equals("≥")) {
384  return GREATER_THAN_EQUAL;
385  } else {
386  throw new IllegalArgumentException("Invalid symbol");
387  }
388  }
389 
393  public String getSymbol() {
394  return symbol;
395  }
396  }
397 
401  static enum SIZE_UNIT {
402 
403  BYTE(1, "Bytes"),
404  KILOBYTE(1024, "Kilobytes"),
405  MEGABYTE(1024 * 1024, "Megabytes"),
406  GIGABYTE(1024 * 1024 * 1024, "Gigabytes");
407  private long size;
408  private String name;
409 
410  private SIZE_UNIT(long size, String name) {
411  this.size = size;
412  this.name = name;
413  }
414 
415  public long getSize() {
416  return this.size;
417  }
418 
419  public static SIZE_UNIT fromName(String name) {
420  for (SIZE_UNIT unit : SIZE_UNIT.values()) {
421  if (unit.getName().equals(name)) {
422  return unit;
423  }
424  }
425  throw new IllegalArgumentException("Invalid name for size unit.");
426  }
427 
431  public String getName() {
432  return name;
433  }
434  }
435  private final COMPARATOR comparator;
436  private final SIZE_UNIT unit;
437  private final int sizeValue;
438 
439  FileSizeCondition(COMPARATOR comparator, SIZE_UNIT unit, int sizeValue) {
440  this.comparator = comparator;
441  this.unit = unit;
442  this.sizeValue = sizeValue;
443  }
444 
450  COMPARATOR getComparator() {
451  return comparator;
452  }
453 
459  SIZE_UNIT getUnit() {
460  return unit;
461  }
462 
468  int getSizeValue() {
469  return sizeValue;
470  }
471 
472  @Override
473  public boolean passes(AbstractFile file) {
474  long fileSize = file.getSize();
475  long conditionSize = this.getUnit().getSize() * this.getSizeValue();
476  switch (this.getComparator()) {
477  case GREATER_THAN:
478  return fileSize > conditionSize;
479  case GREATER_THAN_EQUAL:
480  return fileSize >= conditionSize;
481  case LESS_THAN_EQUAL:
482  return fileSize <= conditionSize;
483  case LESS_THAN:
484  return fileSize < conditionSize;
485  default:
486  return fileSize == conditionSize;
487 
488  }
489  }
490 
491  }
492 
498  static final class MetaTypeCondition implements FileAttributeCondition {
499 
500  private static final long serialVersionUID = 1L;
501 
502  enum Type {
503 
504  FILES,
505  DIRECTORIES,
506  FILES_AND_DIRECTORIES
507  }
508 
509  private final Type type;
510 
516  MetaTypeCondition(Type type) {
517  this.type = type;
518  }
519 
523  @Override
524  public boolean passes(AbstractFile file) {
525  switch (this.type) {
526  case FILES:
527  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG;
528  case DIRECTORIES:
529  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
530  default:
531  return file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_REG
532  || file.getMetaType() == TskData.TSK_FS_META_TYPE_ENUM.TSK_FS_META_TYPE_DIR;
533  }
534  }
535 
541  Type getMetaType() {
542  return this.type;
543  }
544  }
545 
549  static interface TextCondition extends FileAttributeCondition {
550 
556  String getTextToMatch();
557 
565  boolean isRegex();
566 
574  boolean textMatches(String textToMatch);
575 
576  }
577 
582  private static abstract class AbstractTextCondition implements TextCondition {
583 
584  private final TextMatcher textMatcher;
585 
591  AbstractTextCondition(String text, Boolean partialMatch) {
592  if (partialMatch) {
593  this.textMatcher = new FilesSet.Rule.CaseInsensitivePartialStringComparisionMatcher(text);
594  } else {
595  this.textMatcher = new FilesSet.Rule.CaseInsensitiveStringComparisionMatcher(text);
596  }
597  }
598 
604  AbstractTextCondition(Pattern regex) {
605  this.textMatcher = new FilesSet.Rule.RegexMatcher(regex);
606  }
607 
613  @Override
614  public String getTextToMatch() {
615  return this.textMatcher.getTextToMatch();
616  }
617 
625  @Override
626  public boolean isRegex() {
627  return this.textMatcher.isRegex();
628  }
629 
637  @Override
638  public boolean textMatches(String textToMatch) {
639  return this.textMatcher.textMatches(textToMatch);
640  }
641 
645  @Override
646  public abstract boolean passes(AbstractFile file);
647 
648  }
649 
655  static final class ParentPathCondition extends AbstractTextCondition {
656 
657  private static final long serialVersionUID = 1L;
658 
664  ParentPathCondition(String path) {
665  super(path, true);
666  }
667 
673  ParentPathCondition(Pattern path) {
674  super(path);
675  }
676 
680  @Override
681  public boolean passes(AbstractFile file) {
682  return this.textMatches(file.getParentPath() + "/");
683  }
684 
685  }
686 
692  static interface FileNameCondition extends TextCondition {
693  }
694 
700  static final class FullNameCondition extends AbstractTextCondition implements FileNameCondition {
701 
702  private static final long serialVersionUID = 1L;
703 
709  FullNameCondition(String name) {
710  super(name, false);
711  }
712 
718  FullNameCondition(Pattern name) {
719  super(name);
720  }
721 
725  @Override
726  public boolean passes(AbstractFile file) {
727  return this.textMatches(file.getName());
728  }
729 
730  }
731 
737  static final class ExtensionCondition extends AbstractTextCondition implements FileNameCondition {
738 
739  private static final long serialVersionUID = 1L;
740 
746  ExtensionCondition(String extension) {
747  // If there is a leading ".", strip it since
748  // AbstractFile.getFileNameExtension() returns just the
749  // extension chars and not the dot.
750  super(extension.startsWith(".") ? extension.substring(1) : extension, false);
751  }
752 
759  ExtensionCondition(Pattern extension) {
760  super(extension.pattern(), false);
761  }
762 
766  @Override
767  public boolean passes(AbstractFile file) {
768  return this.textMatches(file.getNameExtension());
769  }
770 
771  }
772 
777  private static interface TextMatcher extends Serializable {
778 
784  String getTextToMatch();
785 
793  boolean isRegex();
794 
802  boolean textMatches(String subject);
803 
804  }
805 
809  private static class CaseInsensitiveStringComparisionMatcher implements TextMatcher {
810 
811  private static final long serialVersionUID = 1L;
812  private final String textToMatch;
813 
820  CaseInsensitiveStringComparisionMatcher(String textToMatch) {
821  this.textToMatch = textToMatch;
822  }
823 
827  @Override
828  public String getTextToMatch() {
829  return this.textToMatch;
830  }
831 
835  @Override
836  public boolean isRegex() {
837  return false;
838  }
839 
843  @Override
844  public boolean textMatches(String subject) {
845  return subject.equalsIgnoreCase(textToMatch);
846  }
847 
848  }
849 
854 
855  private static final long serialVersionUID = 1L;
856  private final String textToMatch;
857  private final Pattern pattern;
858 
866  this.textToMatch = textToMatch;
867  this.pattern = Pattern.compile(Pattern.quote(textToMatch), Pattern.CASE_INSENSITIVE);
868  }
869 
873  @Override
874  public String getTextToMatch() {
875  return this.textToMatch;
876  }
877 
881  @Override
882  public boolean isRegex() {
883  return false;
884  }
885 
889  @Override
890  public boolean textMatches(String subject) {
891  return pattern.matcher(subject).find();
892  }
893  }
894 
898  private static class RegexMatcher implements TextMatcher {
899 
900  private static final long serialVersionUID = 1L;
901  private final Pattern regex;
902 
909  RegexMatcher(Pattern regex) {
910  this.regex = regex;
911  }
912 
916  @Override
917  public String getTextToMatch() {
918  return this.regex.pattern();
919  }
920 
924  @Override
925  public boolean isRegex() {
926  return true;
927  }
928 
932  @Override
933  public boolean textMatches(String subject) {
934  // A single match is sufficient.
935  return this.regex.matcher(subject).find();
936  }
937 
938  }
939 
940  }
941 
942 }

Copyright © 2012-2015 Basis Technology. Generated on: Wed Apr 6 2016
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.