Autopsy  4.20.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
InterestingItemsFilesSetSettings.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.File;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.io.Serializable;
26 import java.nio.file.Path;
27 import java.nio.file.Paths;
28 import java.util.Arrays;
29 import java.util.Collection;
30 import java.util.HashMap;
31 import java.util.List;
32 import java.util.Map;
33 import java.util.logging.Level;
34 import java.util.regex.Pattern;
35 import java.util.regex.PatternSyntaxException;
36 import javax.xml.parsers.DocumentBuilder;
37 import javax.xml.parsers.DocumentBuilderFactory;
38 import javax.xml.parsers.ParserConfigurationException;
39 import org.apache.commons.lang.StringUtils;
40 import static org.openide.util.NbBundle.Messages;
41 import org.openide.util.io.NbObjectInputStream;
42 import org.openide.util.io.NbObjectOutputStream;
53 import org.w3c.dom.Document;
54 import org.w3c.dom.Element;
55 import org.w3c.dom.NodeList;
56 import java.util.Comparator;
57 import java.util.function.Function;
58 import java.util.stream.Collectors;
59 
60 class InterestingItemsFilesSetSettings implements Serializable {
61 
62  private static final long serialVersionUID = 1L;
63  // The following tags and attributes are identical to those used in the
64  // TSK Framework FilesSet definitions file schema.
65  private static final String FILE_SETS_ROOT_TAG = "INTERESTING_FILE_SETS"; //NON-NLS
66  private static final String DESC_ATTR = "description"; //NON-NLS
67  private static final String IGNORE_KNOWN_FILES_ATTR = "ignoreKnown"; //NON-NLS
68  private static final String PATH_REGEX_ATTR = "pathRegex"; //NON-NLS
69  private static final String TYPE_FILTER_VALUE_ALL = "all";
70  private static final String TYPE_FILTER_VALUE_FILES_AND_DIRS = "files_and_dirs"; //NON-NLS
71  private static final String IGNORE_UNALLOCATED_SPACE = "ingoreUnallocated"; //NON-NLS
72  private static final String PATH_FILTER_ATTR = "pathFilter"; //NON-NLS
73  private static final String TYPE_FILTER_VALUE_DIRS = "dir"; //NON-NLS
74  private static final String REGEX_ATTR = "regex"; //NON-NLS
75  private static final List<String> illegalFileNameChars = FilesSetsManager.getIllegalFileNameChars();
76  private static final String FILE_SET_TAG = "INTERESTING_FILE_SET"; //NON-NLS
77  private static final String NAME_RULE_TAG = "NAME"; //NON-NLS
78  private static final String NAME_ATTR = "name"; //NON-NLS
79  private static final String DAYS_INCLUDED_ATTR = "daysIncluded";
80  private static final String MIME_ATTR = "mimeType";
81  private static final String FS_COMPARATOR_ATTR = "comparatorSymbol";
82  private static final String FS_SIZE_ATTR = "sizeValue";
83  private static final String FS_UNITS_ATTR = "sizeUnits";
84  private static final String EXCLUSIVE_ATTR = "isExclusive";
85  private static final String TYPE_FILTER_VALUE_FILES = "file"; //NON-NLS
86  private static final String XML_ENCODING = "UTF-8"; //NON-NLS
87  private static final Logger logger = Logger.getLogger(InterestingItemsFilesSetSettings.class.getName());
88  private static final String TYPE_FILTER_ATTR = "typeFilter"; //NON-NLS
89  private static final String EXTENSION_RULE_TAG = "EXTENSION"; //NON-NLS
90  private static final String STANDARD_SET = "standardSet";
91  private static final String VERSION_NUMBER = "versionNumber";
92 
93  private Map<String, FilesSet> filesSets;
94 
95  InterestingItemsFilesSetSettings(Map<String, FilesSet> filesSets) {
96  this.filesSets = filesSets;
97  }
98 
102  Map<String, FilesSet> getFilesSets() {
103  return filesSets;
104  }
105 
113  private static String readRuleName(Element elem) {
114  // The rule must have a name.
115  String ruleName = elem.getAttribute(NAME_ATTR);
116  return ruleName;
117  }
118 
128  @Messages({
129  "# {0} - filePathStr",
130  "InterestingItemsFilesSetSettings.readSerializedDefinitions.failedReadSettings=Failed to read settings from ''{0}''"
131  })
132  private static Map<String, FilesSet> readSerializedDefinitions(String basePath, String serialFileName) throws FilesSetsManager.FilesSetsManagerException {
133  Path filePath = Paths.get(basePath, serialFileName);
134  File fileSetFile = filePath.toFile();
135  String filePathStr = filePath.toString();
136  if (fileSetFile.exists()) {
137  try {
138  try (final NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePathStr))) {
139  InterestingItemsFilesSetSettings filesSetsSettings = (InterestingItemsFilesSetSettings) in.readObject();
140  return filesSetsSettings.getFilesSets();
141  }
142  } catch (IOException | ClassNotFoundException ex) {
143 
144  throw new FilesSetsManager.FilesSetsManagerException(
145  Bundle.InterestingItemsFilesSetSettings_readSerializedDefinitions_failedReadSettings(filePathStr),
146  ex);
147  }
148  } else {
149  return new HashMap<>();
150  }
151  }
152 
164  @Messages({
165  "# {0} - regex",
166  "InterestingItemsFilesSetSettings.readPathCondition.failedCompiledRegex=Error compiling ''{0}'' regex",
167  "# {0} - ruleName",
168  "InterestingItemsFilesSetSettings.readPathCondition.pathConditionCreationError=Error creating path condition for rule ''{0}''"
169  })
170  private static ParentPathCondition readPathCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
171  // Read in the optional path condition. Null is o.k., but if the attribute
172  // is there, be sure it is not malformed.
173  ParentPathCondition pathCondition = null;
174  if (!ruleElement.getAttribute(PATH_FILTER_ATTR).isEmpty() || !ruleElement.getAttribute(PATH_REGEX_ATTR).isEmpty()) {
175  String path = ruleElement.getAttribute(PATH_FILTER_ATTR);
176  String pathRegex = ruleElement.getAttribute(PATH_REGEX_ATTR);
177  if (!pathRegex.isEmpty() && path.isEmpty()) {
178  try {
179  Pattern pattern = Pattern.compile(pathRegex);
180  pathCondition = new ParentPathCondition(pattern);
181  } catch (PatternSyntaxException ex) {
182  logger.log(Level.SEVERE, "Error compiling " + PATH_REGEX_ATTR + " regex, ignoring malformed path condition definition", ex); // NON-NLS
183  throw new FilesSetsManager.FilesSetsManagerException(
184  Bundle.InterestingItemsFilesSetSettings_readPathCondition_failedCompiledRegex(PATH_REGEX_ATTR),
185  ex);
186  }
187  } else if (!path.isEmpty() && pathRegex.isEmpty()) {
188  pathCondition = new ParentPathCondition(path);
189  }
190  if (pathCondition == null) {
191  // Malformed attribute.
192  throw new FilesSetsManager.FilesSetsManagerException(
193  Bundle.InterestingItemsFilesSetSettings_readPathCondition_pathConditionCreationError(readRuleName(ruleElement)));
194  }
195  }
196  return pathCondition;
197  }
198 
210  @Messages({
211  "# {0} - regex",
212  "InterestingItemsFilesSetSettings.readDateCondition.failedCompiledRegex=Error determining ''{0}'' number",})
213  private static DateCondition readDateCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
214  // Read in the optional path condition. Null is o.k., but if the attribute
215  // is there, be sure it is not malformed.
216  DateCondition dateCondition = null;
217  if (!ruleElement.getAttribute(DAYS_INCLUDED_ATTR).isEmpty()) {
218  String daysIncluded = ruleElement.getAttribute(DAYS_INCLUDED_ATTR);
219  if (!daysIncluded.isEmpty()) {
220  try {
221  dateCondition = new DateCondition(Integer.parseInt(daysIncluded));
222  } catch (NumberFormatException ex) {
223  logger.log(Level.SEVERE, "Error creating condition for " + daysIncluded + ", ignoring malformed date condition definition", ex); // NON-NLS
224 
225  throw new FilesSetsManager.FilesSetsManagerException(
226  Bundle.InterestingItemsFilesSetSettings_readDateCondition_failedCompiledRegex(DAYS_INCLUDED_ATTR),
227  ex);
228  }
229  }
230  }
231  return dateCondition;
232  }
233 
241  private static Pattern compileRegex(String regex) {
242  try {
243  return Pattern.compile(regex);
244  } catch (PatternSyntaxException ex) {
245  logger.log(Level.SEVERE, "Error compiling rule regex: " + ex.getMessage(), ex); // NON-NLS
246  return null;
247  }
248  }
249 
262  @Messages({
263  "# {0} - ruleName",
264  "InterestingItemsFilesSetSettings.readRule.missingNecessary=Invalid rule in files set, missing necessary conditions for ''{0}''",})
265  private static FilesSet.Rule readRule(Element elem) throws FilesSetsManager.FilesSetsManagerException {
266  String ruleName = readRuleName(elem);
267  FileNameCondition nameCondition = readNameCondition(elem);
268  MetaTypeCondition metaCondition = readMetaTypeCondition(elem);
269  ParentPathCondition pathCondition = readPathCondition(elem);
270  MimeTypeCondition mimeCondition = readMimeCondition(elem);
271  FileSizeCondition sizeCondition = readSizeCondition(elem);
272  DateCondition dateCondition = readDateCondition(elem); //if meta type condition or all four types of conditions the user can create are all null then don't make the rule
273  Boolean isExclusive = readExclusive(elem);
274  if (metaCondition == null || (nameCondition == null && pathCondition == null && mimeCondition == null && sizeCondition == null && dateCondition == null)) {
275  logger.log(Level.WARNING, "Error Reading Rule, " + ruleName + " was either missing a meta condition or contained only a meta condition. No rule was imported."); // NON-NLS
276 
277  throw new FilesSetsManager.FilesSetsManagerException(
278  Bundle.InterestingItemsFilesSetSettings_readRule_missingNecessary(ruleName));
279  }
280  return new FilesSet.Rule(ruleName, nameCondition, metaCondition, pathCondition, mimeCondition, sizeCondition, dateCondition, isExclusive);
281  }
282 
294  @Messages({
295  "# {0} - tagName",
296  "# {1} - ruleName",
297  "InterestingItemsFilesSetSettings.readNameCondition.invalidTag=Name condition has invalid tag name of ''{0}'' for rule ''{1}''",
298  "# {0} - regex",
299  "# {1} - rule",
300  "InterestingItemsFilesSetSettings.readNameCondition.errorCompilingRegex=Error compiling ''{0}'' regex in rule ''{1}''",
301  "# {0} - character",
302  "# {1} - rule",
303  "InterestingItemsFilesSetSettings.readNameCondition.illegalChar=File name has illegal character of ''{0}'' in rule ''{1}''",})
304  private static FileNameCondition readNameCondition(Element elem) throws FilesSetsManager.FilesSetsManagerException {
305  FileNameCondition nameCondition = null;
306  String content = elem.getTextContent();
307  String regex = elem.getAttribute(REGEX_ATTR);
308  if (content != null && !content.isEmpty()) { //if there isn't content this is not a valid name condition
309  if ((!regex.isEmpty() && regex.equalsIgnoreCase("true")) || content.contains("*")) { // NON-NLS
310  Pattern pattern = compileRegex(content);
311  if (pattern != null) {
312  if (elem.getTagName().equals(NAME_RULE_TAG)) {
313  nameCondition = new FilesSet.Rule.FullNameCondition(pattern);
314  } else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
315  nameCondition = new FilesSet.Rule.ExtensionCondition(pattern);
316  } else {
317  throw new FilesSetsManager.FilesSetsManagerException(
318  Bundle.InterestingItemsFilesSetSettings_readNameCondition_invalidTag(elem.getTagName(), readRuleName(elem)));
319  }
320  } else {
321  logger.log(Level.SEVERE, "Error compiling " + elem.getTagName() + " regex, ignoring malformed ''{0}'' rule definition", readRuleName(elem)); // NON-NLS
322  throw new FilesSetsManager.FilesSetsManagerException(
323  Bundle.InterestingItemsFilesSetSettings_readNameCondition_errorCompilingRegex(REGEX_ATTR, readRuleName(elem)));
324  }
325  } else {
326  for (String illegalChar : illegalFileNameChars) {
327  if (content.contains(illegalChar)) {
328  logger.log(Level.SEVERE, elem.getTagName() + " content has illegal chars, ignoring malformed ''{0}'' rule definition", new Object[]{elem.getTagName(), readRuleName(elem)}); // NON-NLS
329 
330  throw new FilesSetsManager.FilesSetsManagerException(
331  Bundle.InterestingItemsFilesSetSettings_readNameCondition_illegalChar(illegalChar, readRuleName(elem)));
332  }
333  }
334  if (elem.getTagName().equals(NAME_RULE_TAG)) {
335  nameCondition = new FilesSet.Rule.FullNameCondition(content);
336  } else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
337  nameCondition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(content.split(",")));
338  }
339  }
340  }
341  return nameCondition;
342  }
343 
352  private static Boolean readExclusive(Element elem) {
353  Boolean isExclusive = null;
354  if (!elem.getAttribute(EXCLUSIVE_ATTR).isEmpty()) {
355  isExclusive = Boolean.parseBoolean(elem.getAttribute(EXCLUSIVE_ATTR));
356  }
357  return isExclusive;
358  }
359 
368  private static MimeTypeCondition readMimeCondition(Element elem) {
369  MimeTypeCondition mimeCondition = null;
370  if (!elem.getAttribute(MIME_ATTR).isEmpty()) {
371  mimeCondition = new MimeTypeCondition(elem.getAttribute(MIME_ATTR));
372  //no checks on mime type here which means
373  //if they import a rule with a custom MIME type they don't have
374  //the rule will not get any hits
375  }
376  return mimeCondition;
377  }
378 
390  @Messages({
391  "# {0} - rule",
392  "InterestingItemsFilesSetSettings.readSizeCondition.notIntegerValue=Non integer size in files set for rule ''{0}''",
393  "# {0} - rule",
394  "InterestingItemsFilesSetSettings.readSizeCondition.invalidComparator=Invalid comparator or size unit in files set for rule ''{0}''",
395  "# {0} - rule",
396  "InterestingItemsFilesSetSettings.readSizeCondition.malformedXml=Files set is malformed missing at least one 'fileSize' attribute for rule ''{0}''",})
397  private static FileSizeCondition readSizeCondition(Element elem) throws FilesSetsManager.FilesSetsManagerException {
398  FileSizeCondition sizeCondition = null;
399  if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() && !elem.getAttribute(FS_SIZE_ATTR).isEmpty() && !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
400  try { //incase they modified the xml manually to invalid comparator, size unit, or non integer string for size
401  FileSizeCondition.COMPARATOR comparator = FileSizeCondition.COMPARATOR.fromSymbol(elem.getAttribute(FS_COMPARATOR_ATTR));
402  FileSizeCondition.SIZE_UNIT sizeUnit = FileSizeCondition.SIZE_UNIT.fromName(elem.getAttribute(FS_UNITS_ATTR));
403  int size = Integer.parseInt(elem.getAttribute(FS_SIZE_ATTR));
404  sizeCondition = new FileSizeCondition(comparator, sizeUnit, size);
405  } catch (NumberFormatException nfEx) {
406  logger.log(Level.SEVERE, "Value in file size attribute was not an integer, unable to create FileSizeCondition for rule: " + readRuleName(elem), nfEx);
407  throw new FilesSetsManager.FilesSetsManagerException(
408  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_notIntegerValue(readRuleName(elem)),
409  nfEx);
410  } catch (IllegalArgumentException iaEx) {
411  logger.log(Level.SEVERE, "Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem), iaEx);
412  throw new FilesSetsManager.FilesSetsManagerException(
413  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_invalidComparator(readRuleName(elem)),
414  iaEx);
415  }
416  } //if all of them aren't populated but some of them are this is a malformed xml
417  else if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() || !elem.getAttribute(FS_SIZE_ATTR).isEmpty() || !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
418  logger.log(Level.SEVERE, "Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem));
419  throw new FilesSetsManager.FilesSetsManagerException(
420  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_malformedXml(readRuleName(elem)));
421  }
422  return sizeCondition;
423  }
424 
435  private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) throws FilesSetsManager.FilesSetsManagerException {
436  // The file set must have a unique name.
437  String setName = setElem.getAttribute(NAME_ATTR);
438  if (setName.isEmpty()) {
439  logger.log(Level.SEVERE, "Found {0} element without required {1} attribute, ignoring malformed file set definition in FilesSet definition file at {2}", new Object[]{FILE_SET_TAG, NAME_ATTR, filePath}); // NON-NLS
440  return;
441  }
442  if (filesSets.containsKey(setName)) {
443  logger.log(Level.SEVERE, "Found duplicate definition of set named {0} in FilesSet definition file at {1}, discarding duplicate set", new Object[]{setName, filePath}); // NON-NLS
444  return;
445  }
446  // The file set may have a description. The empty string is o.k.
447  String description = setElem.getAttribute(DESC_ATTR);
448  // The file set may or may not ignore known files. The default behavior
449  // is to not ignore them.
450  String ignoreKnown = setElem.getAttribute(IGNORE_KNOWN_FILES_ATTR);
451  boolean ignoreKnownFiles = false;
452  if (!ignoreKnown.isEmpty()) {
453  ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
454  }
455  // The file set may or may not skip unallocated space. The default behavior
456  // is not to skip it.
457  String ignoreUnallocated = setElem.getAttribute(IGNORE_UNALLOCATED_SPACE);
458  boolean ignoreUnallocatedSpace = false;
459  if (!ignoreUnallocated.isEmpty()) {
460  ignoreUnallocatedSpace = Boolean.parseBoolean(ignoreUnallocated);
461  }
462 
463  String isStandardSetString = setElem.getAttribute(STANDARD_SET);
464  boolean isStandardSet = false;
465  if (StringUtils.isNotBlank(isStandardSetString)) {
466  isStandardSet = Boolean.parseBoolean(isStandardSetString);
467  }
468 
469  String versionNumberString = setElem.getAttribute(VERSION_NUMBER);
470  int versionNumber = 0;
471  if (StringUtils.isNotBlank(versionNumberString)) {
472  try {
473  versionNumber = Integer.parseInt(versionNumberString);
474  } catch (NumberFormatException ex) {
475  logger.log(Level.WARNING,
476  String.format("Unable to parse version number for files set named: %s with provided input: '%s'", setName, versionNumberString),
477  ex);
478  }
479  }
480 
481  // Read the set membership rules, if any.
482  Map<String, FilesSet.Rule> rules = new HashMap<>();
483  NodeList allRuleElems = setElem.getChildNodes();
484  for (int j = 0; j < allRuleElems.getLength(); ++j) {
485  if (allRuleElems.item(j) instanceof Element) { //All the children we need to parse here are elements
486  Element elem = (Element) allRuleElems.item(j);
487  FilesSet.Rule rule = readRule(elem);
488  if (rule != null) {
489  if (!rules.containsKey(rule.getUuid())) {
490  rules.put(rule.getUuid(), rule);
491  } else {
492  logger.log(Level.SEVERE, "Found duplicate rule {0} for set named {1} in FilesSet definition file at {2}, discarding malformed set", new Object[]{rule.getUuid(), setName, filePath}); // NON-NLS
493  return;
494  }
495  } else {
496  logger.log(Level.SEVERE, "Found malformed rule for set named {0} in FilesSet definition file at {1}, discarding malformed set", new Object[]{setName, filePath}); // NON-NLS
497  return;
498  }
499  }
500  }
501  // Make the files set. Note that degenerate sets with no rules are
502  // allowed to facilitate the separation of set definition and rule
503  // definitions. A set without rules is simply the empty set.
504  FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isStandardSet, versionNumber);
505  filesSets.put(set.getName(), set);
506  }
507  // Note: This method takes a file path to support the possibility of
508  // multiple intersting files set definition files, e.g., one for
509  // definitions that ship with Autopsy and one for user definitions.
510 
523  static Map<String, FilesSet> readDefinitionsFile(String basePath, String fileName, String legacyFileName) throws FilesSetsManager.FilesSetsManagerException {
524  Map<String, FilesSet> filesSets = readSerializedDefinitions(basePath, fileName);
525  if (!filesSets.isEmpty()) {
526  return filesSets;
527  }
528  // Check if the legacy xml file exists.
529  if (!legacyFileName.isEmpty()) {
530  return readDefinitionsXML(Paths.get(basePath, legacyFileName).toFile());
531  }
532  return filesSets;
533  }
534 
548  static Map<String, FilesSet> readDefinitionsXML(File xmlFile) throws FilesSetsManager.FilesSetsManagerException {
549  if (!xmlFile.exists()) {
550  return new HashMap<>();
551  }
552  // Check if the file can be read.
553  if (!xmlFile.canRead()) {
554  logger.log(Level.SEVERE, "FilesSet definition file at {0} exists, but cannot be read", xmlFile.getPath()); // NON-NLS
555  return new HashMap<>();
556  }
557 
558  Document doc = XMLUtil.loadDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath());
559  return readDefinitionsXML(doc, xmlFile.getPath());
560  }
561 
575  static Map<String, FilesSet> readDefinitionsXML(Document doc, String resourceName) throws FilesSetsManager.FilesSetsManagerException {
576  // Parse the XML in the file.
577  Map<String, FilesSet> filesSets = new HashMap<>();
578 
579  if (doc == null) {
580  logger.log(Level.SEVERE, "FilesSet definition file at {0}", resourceName); // NON-NLS
581  return filesSets;
582  }
583  // Get the root element.
584  Element root = doc.getDocumentElement();
585  if (root == null) {
586  logger.log(Level.SEVERE, "Failed to get root {0} element tag of FilesSet definition file at {1}",
587  new Object[]{FILE_SETS_ROOT_TAG, resourceName}); // NON-NLS
588  return filesSets;
589  }
590  // Read in the files set definitions.
591  NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
592  for (int i = 0; i < setElems.getLength(); ++i) {
593  readFilesSet((Element) setElems.item(i), filesSets, resourceName);
594  }
595  return filesSets;
596  }
597 
598  // Note: This method takes a file path to support the possibility of
599  // multiple intersting files set definition files, e.g., one for
600  // definitions that ship with Autopsy and one for user definitions.
608  static boolean writeDefinitionsFile(String basePath, String fileName, Map<String, FilesSet> interestingFilesSets) throws FilesSetsManager.FilesSetsManagerException {
609  File outputFile = Paths.get(basePath, fileName).toFile();
610  outputFile.getParentFile().mkdirs();
611  try (final NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(outputFile))) {
612  out.writeObject(new InterestingItemsFilesSetSettings(interestingFilesSets));
613  } catch (IOException ex) {
614  throw new FilesSetsManager.FilesSetsManagerException(String.format("Failed to write settings to %s", fileName), ex);
615  }
616  return true;
617  }
618 
619 
626  private static <T> List<T> sortOnField(Collection<T> itemsToSort, final Function<T, String> getName) {
627  Comparator<T> comparator = (a,b) -> {
628  String aName = getName.apply(a);
629  String bName = getName.apply(b);
630  if (aName == null) {
631  aName = "";
632  }
633 
634  if (bName == null) {
635  bName = "";
636  }
637 
638  return aName.compareToIgnoreCase(bName);
639  };
640 
641  return itemsToSort.stream()
642  .sorted(comparator)
643  .collect(Collectors.toList());
644  }
645 
646 
656  static boolean exportXmlDefinitionsFile(File xmlFile, List<FilesSet> interestingFilesSets) {
657  DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
658  try {
659  // Create the new XML document.
660  DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
661  Document doc = docBuilder.newDocument();
662  Element rootElement = doc.createElement(FILE_SETS_ROOT_TAG);
663  doc.appendChild(rootElement);
664  // Add the interesting files sets to the document.
665 
666  List<FilesSet> sortedFilesSets = sortOnField(
667  interestingFilesSets,
668  filesSet -> filesSet == null ? null : filesSet.getName());
669 
670  for (FilesSet set : sortedFilesSets) {
671  // Add the files set element and its attributes.
672  Element setElement = doc.createElement(FILE_SET_TAG);
673  setElement.setAttribute(NAME_ATTR, set.getName());
674  setElement.setAttribute(DESC_ATTR, set.getDescription());
675  setElement.setAttribute(IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles()));
676  setElement.setAttribute(STANDARD_SET, Boolean.toString(set.isStandardSet()));
677  setElement.setAttribute(VERSION_NUMBER, Integer.toString(set.getVersionNumber()));
678  // Add the child elements for the set membership rules.
679  // All conditions of a rule will be written as a single element in the xml
680 
681  List<FilesSet.Rule> sortedRules = sortOnField(
682  set.getRules().values(),
683  rule -> rule == null ? null : rule.getName());
684 
685  for (FilesSet.Rule rule : sortedRules) {
686  // Add a rule element with the appropriate name Condition
687  // type tag.
688  Element ruleElement;
689 
690  FileNameCondition nameCondition = rule.getFileNameCondition();
691  //The element type is just being used as another attribute for
692  //the name condition in legacy xmls.
693  //For rules which don't contain a name condition it doesn't matter
694  //what type of element it is
695  if (nameCondition instanceof FilesSet.Rule.FullNameCondition) {
696  ruleElement = doc.createElement(NAME_RULE_TAG);
697  } else {
698  ruleElement = doc.createElement(EXTENSION_RULE_TAG);
699  }
700  // Add the optional rule name attribute.
701  ruleElement.setAttribute(NAME_ATTR, rule.getName());
702  if (nameCondition != null) {
703  // Add the name Condition regex attribute
704  ruleElement.setAttribute(REGEX_ATTR, Boolean.toString(nameCondition.isRegex()));
705  // Add the name Condition text as the rule element content.
706  ruleElement.setTextContent(nameCondition.getTextToMatch());
707  }
708  // Add the type Condition attribute.
709  MetaTypeCondition typeCondition = rule.getMetaTypeCondition();
710  switch (typeCondition.getMetaType()) {
711  case FILES:
712  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_FILES);
713  break;
714  case DIRECTORIES:
715  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_DIRS);
716  break;
717  default:
718  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_ALL);
719  break;
720  }
721  // Add the optional path Condition.
722  ParentPathCondition pathCondition = rule.getPathCondition();
723  if (pathCondition != null) {
724  if (pathCondition.isRegex()) {
725  ruleElement.setAttribute(PATH_REGEX_ATTR, pathCondition.getTextToMatch());
726  } else {
727  ruleElement.setAttribute(PATH_FILTER_ATTR, pathCondition.getTextToMatch());
728  }
729  }
730  //Add the optional MIME type condition
731  MimeTypeCondition mimeCondition = rule.getMimeTypeCondition();
732  if (mimeCondition != null) {
733  ruleElement.setAttribute(MIME_ATTR, mimeCondition.getMimeType());
734  }
735  //Add the optional file size condition
736  FileSizeCondition sizeCondition = rule.getFileSizeCondition();
737  if (sizeCondition != null) {
738  ruleElement.setAttribute(FS_COMPARATOR_ATTR, sizeCondition.getComparator().getSymbol());
739  ruleElement.setAttribute(FS_SIZE_ATTR, Integer.toString(sizeCondition.getSizeValue()));
740  ruleElement.setAttribute(FS_UNITS_ATTR, sizeCondition.getUnit().getName());
741  }
742 
743  //Add the optional date condition
744  DateCondition dateCondition = rule.getDateCondition();
745  if (dateCondition != null) {
746  ruleElement.setAttribute(DAYS_INCLUDED_ATTR, Integer.toString(dateCondition.getDaysIncluded()));
747  }
748 
749  ruleElement.setAttribute(EXCLUSIVE_ATTR, Boolean.toString(rule.isExclusive()));
750 
751  setElement.appendChild(ruleElement);
752  }
753  rootElement.appendChild(setElement);
754  }
755  // Overwrite the previous definitions file. Note that the utility
756  // method logs an error on failure.
757  return XMLUtil.saveDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath(), XML_ENCODING, doc);
758  } catch (ParserConfigurationException ex) {
759  logger.log(Level.SEVERE, "Error writing interesting files definition file to " + xmlFile.getPath(), ex); // NON-NLS
760  return false;
761  }
762  }
763 
775  @Messages({
776  "# {0} - condition",
777  "# {1} - rule",
778  "InterestingItemsFilesSetSettings.readMetaTypeCondition.malformedXml=Files set is malformed for metatype condition, ''{0}'', in rule ''{1}''"
779  })
780  private static MetaTypeCondition readMetaTypeCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
781  MetaTypeCondition metaCondition = null;
782  // The rule must have a meta-type condition, unless a TSK Framework
783  // definitions file is being read.
784  if (!ruleElement.getAttribute(TYPE_FILTER_ATTR).isEmpty()) {
785  String conditionAttribute = ruleElement.getAttribute(TYPE_FILTER_ATTR);
786  if (!conditionAttribute.isEmpty()) {
787  switch (conditionAttribute) {
788  case TYPE_FILTER_VALUE_FILES:
789  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.FILES);
790  break;
791  case TYPE_FILTER_VALUE_DIRS:
792  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.DIRECTORIES);
793  break;
794  case TYPE_FILTER_VALUE_ALL:
795  case TYPE_FILTER_VALUE_FILES_AND_DIRS: //converts legacy xmls to current metaCondition terms
796  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.ALL);
797  break;
798  default:
799  logger.log(Level.SEVERE, "Found {0} " + TYPE_FILTER_ATTR + " attribute with unrecognized value ''{0}'', ignoring malformed rule definition", conditionAttribute); // NON-NLS
800  // Malformed attribute.
801 
802  throw new FilesSetsManager.FilesSetsManagerException(
803  Bundle.InterestingItemsFilesSetSettings_readMetaTypeCondition_malformedXml(
804  conditionAttribute, readRuleName(ruleElement)));
805  }
806  }
807  }
808  if (metaCondition == null) {
809  // Accept TSK Framework FilesSet definitions,
810  // default to files.
811  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.FILES);
812  }
813  return metaCondition;
814  }
815 }

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