Autopsy  4.17.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 TYPE_FILTER_VALUE_FILES = "file"; //NON-NLS
85  private static final String XML_ENCODING = "UTF-8"; //NON-NLS
86  private static final Logger logger = Logger.getLogger(InterestingItemsFilesSetSettings.class.getName());
87  private static final String TYPE_FILTER_ATTR = "typeFilter"; //NON-NLS
88  private static final String EXTENSION_RULE_TAG = "EXTENSION"; //NON-NLS
89  private static final String STANDARD_SET = "standardSet";
90  private static final String VERSION_NUMBER = "versionNumber";
91 
92  private Map<String, FilesSet> filesSets;
93 
94  InterestingItemsFilesSetSettings(Map<String, FilesSet> filesSets) {
95  this.filesSets = filesSets;
96  }
97 
101  Map<String, FilesSet> getFilesSets() {
102  return filesSets;
103  }
104 
112  private static String readRuleName(Element elem) {
113  // The rule must have a name.
114  String ruleName = elem.getAttribute(NAME_ATTR);
115  return ruleName;
116  }
117 
126  @Messages({
127  "# {0} - filePathStr",
128  "InterestingItemsFilesSetSettings.readSerializedDefinitions.failedReadSettings=Failed to read settings from ''{0}''"
129  })
130  private static Map<String, FilesSet> readSerializedDefinitions(String serialFileName) throws FilesSetsManager.FilesSetsManagerException {
131  Path filePath = Paths.get(PlatformUtil.getUserConfigDirectory(), serialFileName);
132  File fileSetFile = filePath.toFile();
133  String filePathStr = filePath.toString();
134  if (fileSetFile.exists()) {
135  try {
136  try (final NbObjectInputStream in = new NbObjectInputStream(new FileInputStream(filePathStr))) {
137  InterestingItemsFilesSetSettings filesSetsSettings = (InterestingItemsFilesSetSettings) in.readObject();
138  return filesSetsSettings.getFilesSets();
139  }
140  } catch (IOException | ClassNotFoundException ex) {
141 
142  throw new FilesSetsManager.FilesSetsManagerException(
143  Bundle.InterestingItemsFilesSetSettings_readSerializedDefinitions_failedReadSettings(filePathStr),
144  ex);
145  }
146  } else {
147  return new HashMap<>();
148  }
149  }
150 
162  @Messages({
163  "# {0} - regex",
164  "InterestingItemsFilesSetSettings.readPathCondition.failedCompiledRegex=Error compiling ''{0}'' regex",
165  "# {0} - ruleName",
166  "InterestingItemsFilesSetSettings.readPathCondition.pathConditionCreationError=Error creating path condition for rule ''{0}''"
167  })
168  private static ParentPathCondition readPathCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
169  // Read in the optional path condition. Null is o.k., but if the attribute
170  // is there, be sure it is not malformed.
171  ParentPathCondition pathCondition = null;
172  if (!ruleElement.getAttribute(PATH_FILTER_ATTR).isEmpty() || !ruleElement.getAttribute(PATH_REGEX_ATTR).isEmpty()) {
173  String path = ruleElement.getAttribute(PATH_FILTER_ATTR);
174  String pathRegex = ruleElement.getAttribute(PATH_REGEX_ATTR);
175  if (!pathRegex.isEmpty() && path.isEmpty()) {
176  try {
177  Pattern pattern = Pattern.compile(pathRegex);
178  pathCondition = new ParentPathCondition(pattern);
179  } catch (PatternSyntaxException ex) {
180  logger.log(Level.SEVERE, "Error compiling " + PATH_REGEX_ATTR + " regex, ignoring malformed path condition definition", ex); // NON-NLS
181  throw new FilesSetsManager.FilesSetsManagerException(
182  Bundle.InterestingItemsFilesSetSettings_readPathCondition_failedCompiledRegex(PATH_REGEX_ATTR),
183  ex);
184  }
185  } else if (!path.isEmpty() && pathRegex.isEmpty()) {
186  pathCondition = new ParentPathCondition(path);
187  }
188  if (pathCondition == null) {
189  // Malformed attribute.
190  throw new FilesSetsManager.FilesSetsManagerException(
191  Bundle.InterestingItemsFilesSetSettings_readPathCondition_pathConditionCreationError(readRuleName(ruleElement)));
192  }
193  }
194  return pathCondition;
195  }
196 
208  @Messages({
209  "# {0} - regex",
210  "InterestingItemsFilesSetSettings.readDateCondition.failedCompiledRegex=Error determining ''{0}'' number",})
211  private static DateCondition readDateCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
212  // Read in the optional path condition. Null is o.k., but if the attribute
213  // is there, be sure it is not malformed.
214  DateCondition dateCondition = null;
215  if (!ruleElement.getAttribute(DAYS_INCLUDED_ATTR).isEmpty()) {
216  String daysIncluded = ruleElement.getAttribute(DAYS_INCLUDED_ATTR);
217  if (!daysIncluded.isEmpty()) {
218  try {
219  dateCondition = new DateCondition(Integer.parseInt(daysIncluded));
220  } catch (NumberFormatException ex) {
221  logger.log(Level.SEVERE, "Error creating condition for " + daysIncluded + ", ignoring malformed date condition definition", ex); // NON-NLS
222 
223  throw new FilesSetsManager.FilesSetsManagerException(
224  Bundle.InterestingItemsFilesSetSettings_readDateCondition_failedCompiledRegex(DAYS_INCLUDED_ATTR),
225  ex);
226  }
227  }
228  }
229  return dateCondition;
230  }
231 
239  private static Pattern compileRegex(String regex) {
240  try {
241  return Pattern.compile(regex);
242  } catch (PatternSyntaxException ex) {
243  logger.log(Level.SEVERE, "Error compiling rule regex: " + ex.getMessage(), ex); // NON-NLS
244  return null;
245  }
246  }
247 
260  @Messages({
261  "# {0} - ruleName",
262  "InterestingItemsFilesSetSettings.readRule.missingNecessary=Invalid rule in files set, missing necessary conditions for ''{0}''",})
263  private static FilesSet.Rule readRule(Element elem) throws FilesSetsManager.FilesSetsManagerException {
264  String ruleName = readRuleName(elem);
265  FileNameCondition nameCondition = readNameCondition(elem);
266  MetaTypeCondition metaCondition = readMetaTypeCondition(elem);
267  ParentPathCondition pathCondition = readPathCondition(elem);
268  MimeTypeCondition mimeCondition = readMimeCondition(elem);
269  FileSizeCondition sizeCondition = readSizeCondition(elem);
270  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
271  if (metaCondition == null || (nameCondition == null && pathCondition == null && mimeCondition == null && sizeCondition == null && dateCondition == null)) {
272  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
273 
274  throw new FilesSetsManager.FilesSetsManagerException(
275  Bundle.InterestingItemsFilesSetSettings_readRule_missingNecessary(ruleName));
276  }
277  return new FilesSet.Rule(ruleName, nameCondition, metaCondition, pathCondition, mimeCondition, sizeCondition, dateCondition);
278  }
279 
291  @Messages({
292  "# {0} - tagName",
293  "# {1} - ruleName",
294  "InterestingItemsFilesSetSettings.readNameCondition.invalidTag=Name condition has invalid tag name of ''{0}'' for rule ''{1}''",
295  "# {0} - regex",
296  "# {1} - rule",
297  "InterestingItemsFilesSetSettings.readNameCondition.errorCompilingRegex=Error compiling ''{0}'' regex in rule ''{1}''",
298  "# {0} - character",
299  "# {1} - rule",
300  "InterestingItemsFilesSetSettings.readNameCondition.illegalChar=File name has illegal character of ''{0}'' in rule ''{1}''",})
301  private static FileNameCondition readNameCondition(Element elem) throws FilesSetsManager.FilesSetsManagerException {
302  FileNameCondition nameCondition = null;
303  String content = elem.getTextContent();
304  String regex = elem.getAttribute(REGEX_ATTR);
305  if (content != null && !content.isEmpty()) { //if there isn't content this is not a valid name condition
306  if ((!regex.isEmpty() && regex.equalsIgnoreCase("true")) || content.contains("*")) { // NON-NLS
307  Pattern pattern = compileRegex(content);
308  if (pattern != null) {
309  if (elem.getTagName().equals(NAME_RULE_TAG)) {
310  nameCondition = new FilesSet.Rule.FullNameCondition(pattern);
311  } else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
312  nameCondition = new FilesSet.Rule.ExtensionCondition(pattern);
313  } else {
314  throw new FilesSetsManager.FilesSetsManagerException(
315  Bundle.InterestingItemsFilesSetSettings_readNameCondition_invalidTag(elem.getTagName(), readRuleName(elem)));
316  }
317  } else {
318  logger.log(Level.SEVERE, "Error compiling " + elem.getTagName() + " regex, ignoring malformed ''{0}'' rule definition", readRuleName(elem)); // NON-NLS
319  throw new FilesSetsManager.FilesSetsManagerException(
320  Bundle.InterestingItemsFilesSetSettings_readNameCondition_errorCompilingRegex(REGEX_ATTR, readRuleName(elem)));
321  }
322  } else {
323  for (String illegalChar : illegalFileNameChars) {
324  if (content.contains(illegalChar)) {
325  logger.log(Level.SEVERE, elem.getTagName() + " content has illegal chars, ignoring malformed ''{0}'' rule definition", new Object[]{elem.getTagName(), readRuleName(elem)}); // NON-NLS
326 
327  throw new FilesSetsManager.FilesSetsManagerException(
328  Bundle.InterestingItemsFilesSetSettings_readNameCondition_illegalChar(illegalChar, readRuleName(elem)));
329  }
330  }
331  if (elem.getTagName().equals(NAME_RULE_TAG)) {
332  nameCondition = new FilesSet.Rule.FullNameCondition(content);
333  } else if (elem.getTagName().equals(EXTENSION_RULE_TAG)) {
334  nameCondition = new FilesSet.Rule.ExtensionCondition(Arrays.asList(content.split(",")));
335  }
336  }
337  }
338  return nameCondition;
339  }
340 
349  private static MimeTypeCondition readMimeCondition(Element elem) {
350  MimeTypeCondition mimeCondition = null;
351  if (!elem.getAttribute(MIME_ATTR).isEmpty()) {
352  mimeCondition = new MimeTypeCondition(elem.getAttribute(MIME_ATTR));
353  //no checks on mime type here which means
354  //if they import a rule with a custom MIME type they don't have
355  //the rule will not get any hits
356  }
357  return mimeCondition;
358  }
359 
371  @Messages({
372  "# {0} - rule",
373  "InterestingItemsFilesSetSettings.readSizeCondition.notIntegerValue=Non integer size in files set for rule ''{0}''",
374  "# {0} - rule",
375  "InterestingItemsFilesSetSettings.readSizeCondition.invalidComparator=Invalid comparator or size unit in files set for rule ''{0}''",
376  "# {0} - rule",
377  "InterestingItemsFilesSetSettings.readSizeCondition.malformedXml=Files set is malformed missing at least one 'fileSize' attribute for rule ''{0}''",})
378  private static FileSizeCondition readSizeCondition(Element elem) throws FilesSetsManager.FilesSetsManagerException {
379  FileSizeCondition sizeCondition = null;
380  if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() && !elem.getAttribute(FS_SIZE_ATTR).isEmpty() && !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
381  try { //incase they modified the xml manually to invalid comparator, size unit, or non integer string for size
382  FileSizeCondition.COMPARATOR comparator = FileSizeCondition.COMPARATOR.fromSymbol(elem.getAttribute(FS_COMPARATOR_ATTR));
383  FileSizeCondition.SIZE_UNIT sizeUnit = FileSizeCondition.SIZE_UNIT.fromName(elem.getAttribute(FS_UNITS_ATTR));
384  int size = Integer.parseInt(elem.getAttribute(FS_SIZE_ATTR));
385  sizeCondition = new FileSizeCondition(comparator, sizeUnit, size);
386  } catch (NumberFormatException nfEx) {
387  logger.log(Level.SEVERE, "Value in file size attribute was not an integer, unable to create FileSizeCondition for rule: " + readRuleName(elem), nfEx);
388  throw new FilesSetsManager.FilesSetsManagerException(
389  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_notIntegerValue(readRuleName(elem)),
390  nfEx);
391  } catch (IllegalArgumentException iaEx) {
392  logger.log(Level.SEVERE, "Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem), iaEx);
393  throw new FilesSetsManager.FilesSetsManagerException(
394  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_invalidComparator(readRuleName(elem)),
395  iaEx);
396  }
397  } //if all of them aren't populated but some of them are this is a malformed xml
398  else if (!elem.getAttribute(FS_COMPARATOR_ATTR).isEmpty() || !elem.getAttribute(FS_SIZE_ATTR).isEmpty() || !elem.getAttribute(FS_UNITS_ATTR).isEmpty()) {
399  logger.log(Level.SEVERE, "Invalid Comparator symbol or Size Unit set in FilesSet xml, unable to create FileSizeCondition for rule: " + readRuleName(elem));
400  throw new FilesSetsManager.FilesSetsManagerException(
401  Bundle.InterestingItemsFilesSetSettings_readSizeCondition_malformedXml(readRuleName(elem)));
402  }
403  return sizeCondition;
404  }
405 
416  private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) throws FilesSetsManager.FilesSetsManagerException {
417  // The file set must have a unique name.
418  String setName = setElem.getAttribute(NAME_ATTR);
419  if (setName.isEmpty()) {
420  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
421  return;
422  }
423  if (filesSets.containsKey(setName)) {
424  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
425  return;
426  }
427  // The file set may have a description. The empty string is o.k.
428  String description = setElem.getAttribute(DESC_ATTR);
429  // The file set may or may not ignore known files. The default behavior
430  // is to not ignore them.
431  String ignoreKnown = setElem.getAttribute(IGNORE_KNOWN_FILES_ATTR);
432  boolean ignoreKnownFiles = false;
433  if (!ignoreKnown.isEmpty()) {
434  ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
435  }
436  // The file set may or may not skip unallocated space. The default behavior
437  // is not to skip it.
438  String ignoreUnallocated = setElem.getAttribute(IGNORE_UNALLOCATED_SPACE);
439  boolean ignoreUnallocatedSpace = false;
440  if (!ignoreUnallocated.isEmpty()) {
441  ignoreUnallocatedSpace = Boolean.parseBoolean(ignoreUnallocated);
442  }
443 
444  String isStandardSetString = setElem.getAttribute(STANDARD_SET);
445  boolean isStandardSet = false;
446  if (StringUtils.isNotBlank(isStandardSetString)) {
447  isStandardSet = Boolean.parseBoolean(isStandardSetString);
448  }
449 
450  String versionNumberString = setElem.getAttribute(VERSION_NUMBER);
451  int versionNumber = 0;
452  if (StringUtils.isNotBlank(versionNumberString)) {
453  try {
454  versionNumber = Integer.parseInt(versionNumberString);
455  } catch (NumberFormatException ex) {
456  logger.log(Level.WARNING,
457  String.format("Unable to parse version number for files set named: %s with provided input: '%s'", setName, versionNumberString),
458  ex);
459  }
460  }
461 
462  // Read the set membership rules, if any.
463  Map<String, FilesSet.Rule> rules = new HashMap<>();
464  NodeList allRuleElems = setElem.getChildNodes();
465  for (int j = 0; j < allRuleElems.getLength(); ++j) {
466  if (allRuleElems.item(j) instanceof Element) { //All the children we need to parse here are elements
467  Element elem = (Element) allRuleElems.item(j);
468  FilesSet.Rule rule = readRule(elem);
469  if (rule != null) {
470  if (!rules.containsKey(rule.getUuid())) {
471  rules.put(rule.getUuid(), rule);
472  } else {
473  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
474  return;
475  }
476  } else {
477  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
478  return;
479  }
480  }
481  }
482  // Make the files set. Note that degenerate sets with no rules are
483  // allowed to facilitate the separation of set definition and rule
484  // definitions. A set without rules is simply the empty set.
485  FilesSet set = new FilesSet(setName, description, ignoreKnownFiles, ignoreUnallocatedSpace, rules, isStandardSet, versionNumber);
486  filesSets.put(set.getName(), set);
487  }
488  // Note: This method takes a file path to support the possibility of
489  // multiple intersting files set definition files, e.g., one for
490  // definitions that ship with Autopsy and one for user definitions.
491 
504  static Map<String, FilesSet> readDefinitionsFile(String fileName, String legacyFileName) throws FilesSetsManager.FilesSetsManagerException {
505  Map<String, FilesSet> filesSets = readSerializedDefinitions(fileName);
506  if (!filesSets.isEmpty()) {
507  return filesSets;
508  }
509  // Check if the legacy xml file exists.
510  if (!legacyFileName.isEmpty()) {
511  return readDefinitionsXML(Paths.get(PlatformUtil.getUserConfigDirectory(), legacyFileName).toFile());
512  }
513  return filesSets;
514  }
515 
529  static Map<String, FilesSet> readDefinitionsXML(File xmlFile) throws FilesSetsManager.FilesSetsManagerException {
530  if (!xmlFile.exists()) {
531  return new HashMap<>();
532  }
533  // Check if the file can be read.
534  if (!xmlFile.canRead()) {
535  logger.log(Level.SEVERE, "FilesSet definition file at {0} exists, but cannot be read", xmlFile.getPath()); // NON-NLS
536  return new HashMap<>();
537  }
538 
539  Document doc = XMLUtil.loadDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath());
540  return readDefinitionsXML(doc, xmlFile.getPath());
541  }
542 
556  static Map<String, FilesSet> readDefinitionsXML(Document doc, String resourceName) throws FilesSetsManager.FilesSetsManagerException {
557  // Parse the XML in the file.
558  Map<String, FilesSet> filesSets = new HashMap<>();
559 
560  if (doc == null) {
561  logger.log(Level.SEVERE, "FilesSet definition file at {0}", resourceName); // NON-NLS
562  return filesSets;
563  }
564  // Get the root element.
565  Element root = doc.getDocumentElement();
566  if (root == null) {
567  logger.log(Level.SEVERE, "Failed to get root {0} element tag of FilesSet definition file at {1}",
568  new Object[]{FILE_SETS_ROOT_TAG, resourceName}); // NON-NLS
569  return filesSets;
570  }
571  // Read in the files set definitions.
572  NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
573  for (int i = 0; i < setElems.getLength(); ++i) {
574  readFilesSet((Element) setElems.item(i), filesSets, resourceName);
575  }
576  return filesSets;
577  }
578 
579  // Note: This method takes a file path to support the possibility of
580  // multiple intersting files set definition files, e.g., one for
581  // definitions that ship with Autopsy and one for user definitions.
589  static boolean writeDefinitionsFile(String fileName, Map<String, FilesSet> interestingFilesSets) throws FilesSetsManager.FilesSetsManagerException {
590  try (final NbObjectOutputStream out = new NbObjectOutputStream(new FileOutputStream(Paths.get(PlatformUtil.getUserConfigDirectory(), fileName).toString()))) {
591  out.writeObject(new InterestingItemsFilesSetSettings(interestingFilesSets));
592  } catch (IOException ex) {
593  throw new FilesSetsManager.FilesSetsManagerException(String.format("Failed to write settings to %s", fileName), ex);
594  }
595  return true;
596  }
597 
598 
605  private static <T> List<T> sortOnField(Collection<T> itemsToSort, final Function<T, String> getName) {
606  Comparator<T> comparator = (a,b) -> {
607  String aName = getName.apply(a);
608  String bName = getName.apply(b);
609  if (aName == null) {
610  aName = "";
611  }
612 
613  if (bName == null) {
614  bName = "";
615  }
616 
617  return aName.compareToIgnoreCase(bName);
618  };
619 
620  return itemsToSort.stream()
621  .sorted(comparator)
622  .collect(Collectors.toList());
623  }
624 
625 
635  static boolean exportXmlDefinitionsFile(File xmlFile, List<FilesSet> interestingFilesSets) {
636  DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
637  try {
638  // Create the new XML document.
639  DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
640  Document doc = docBuilder.newDocument();
641  Element rootElement = doc.createElement(FILE_SETS_ROOT_TAG);
642  doc.appendChild(rootElement);
643  // Add the interesting files sets to the document.
644 
645  List<FilesSet> sortedFilesSets = sortOnField(
646  interestingFilesSets,
647  filesSet -> filesSet == null ? null : filesSet.getName());
648 
649  for (FilesSet set : sortedFilesSets) {
650  // Add the files set element and its attributes.
651  Element setElement = doc.createElement(FILE_SET_TAG);
652  setElement.setAttribute(NAME_ATTR, set.getName());
653  setElement.setAttribute(DESC_ATTR, set.getDescription());
654  setElement.setAttribute(IGNORE_KNOWN_FILES_ATTR, Boolean.toString(set.ignoresKnownFiles()));
655  setElement.setAttribute(STANDARD_SET, Boolean.toString(set.isStandardSet()));
656  setElement.setAttribute(VERSION_NUMBER, Integer.toString(set.getVersionNumber()));
657  // Add the child elements for the set membership rules.
658  // All conditions of a rule will be written as a single element in the xml
659 
660  List<FilesSet.Rule> sortedRules = sortOnField(
661  set.getRules().values(),
662  rule -> rule == null ? null : rule.getName());
663 
664  for (FilesSet.Rule rule : sortedRules) {
665  // Add a rule element with the appropriate name Condition
666  // type tag.
667  Element ruleElement;
668 
669  FileNameCondition nameCondition = rule.getFileNameCondition();
670  //The element type is just being used as another attribute for
671  //the name condition in legacy xmls.
672  //For rules which don't contain a name condition it doesn't matter
673  //what type of element it is
674  if (nameCondition instanceof FilesSet.Rule.FullNameCondition) {
675  ruleElement = doc.createElement(NAME_RULE_TAG);
676  } else {
677  ruleElement = doc.createElement(EXTENSION_RULE_TAG);
678  }
679  // Add the optional rule name attribute.
680  ruleElement.setAttribute(NAME_ATTR, rule.getName());
681  if (nameCondition != null) {
682  // Add the name Condition regex attribute
683  ruleElement.setAttribute(REGEX_ATTR, Boolean.toString(nameCondition.isRegex()));
684  // Add the name Condition text as the rule element content.
685  ruleElement.setTextContent(nameCondition.getTextToMatch());
686  }
687  // Add the type Condition attribute.
688  MetaTypeCondition typeCondition = rule.getMetaTypeCondition();
689  switch (typeCondition.getMetaType()) {
690  case FILES:
691  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_FILES);
692  break;
693  case DIRECTORIES:
694  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_DIRS);
695  break;
696  default:
697  ruleElement.setAttribute(TYPE_FILTER_ATTR, TYPE_FILTER_VALUE_ALL);
698  break;
699  }
700  // Add the optional path Condition.
701  ParentPathCondition pathCondition = rule.getPathCondition();
702  if (pathCondition != null) {
703  if (pathCondition.isRegex()) {
704  ruleElement.setAttribute(PATH_REGEX_ATTR, pathCondition.getTextToMatch());
705  } else {
706  ruleElement.setAttribute(PATH_FILTER_ATTR, pathCondition.getTextToMatch());
707  }
708  }
709  //Add the optional MIME type condition
710  MimeTypeCondition mimeCondition = rule.getMimeTypeCondition();
711  if (mimeCondition != null) {
712  ruleElement.setAttribute(MIME_ATTR, mimeCondition.getMimeType());
713  }
714  //Add the optional file size condition
715  FileSizeCondition sizeCondition = rule.getFileSizeCondition();
716  if (sizeCondition != null) {
717  ruleElement.setAttribute(FS_COMPARATOR_ATTR, sizeCondition.getComparator().getSymbol());
718  ruleElement.setAttribute(FS_SIZE_ATTR, Integer.toString(sizeCondition.getSizeValue()));
719  ruleElement.setAttribute(FS_UNITS_ATTR, sizeCondition.getUnit().getName());
720  }
721 
722  //Add the optional date condition
723  DateCondition dateCondition = rule.getDateCondition();
724  if (dateCondition != null) {
725  ruleElement.setAttribute(DAYS_INCLUDED_ATTR, Integer.toString(dateCondition.getDaysIncluded()));
726  }
727 
728  setElement.appendChild(ruleElement);
729  }
730  rootElement.appendChild(setElement);
731  }
732  // Overwrite the previous definitions file. Note that the utility
733  // method logs an error on failure.
734  return XMLUtil.saveDoc(InterestingItemsFilesSetSettings.class, xmlFile.getPath(), XML_ENCODING, doc);
735  } catch (ParserConfigurationException ex) {
736  logger.log(Level.SEVERE, "Error writing interesting files definition file to " + xmlFile.getPath(), ex); // NON-NLS
737  return false;
738  }
739  }
740 
752  @Messages({
753  "# {0} - condition",
754  "# {1} - rule",
755  "InterestingItemsFilesSetSettings.readMetaTypeCondition.malformedXml=Files set is malformed for metatype condition, ''{0}'', in rule ''{1}''"
756  })
757  private static MetaTypeCondition readMetaTypeCondition(Element ruleElement) throws FilesSetsManager.FilesSetsManagerException {
758  MetaTypeCondition metaCondition = null;
759  // The rule must have a meta-type condition, unless a TSK Framework
760  // definitions file is being read.
761  if (!ruleElement.getAttribute(TYPE_FILTER_ATTR).isEmpty()) {
762  String conditionAttribute = ruleElement.getAttribute(TYPE_FILTER_ATTR);
763  if (!conditionAttribute.isEmpty()) {
764  switch (conditionAttribute) {
765  case TYPE_FILTER_VALUE_FILES:
766  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.FILES);
767  break;
768  case TYPE_FILTER_VALUE_DIRS:
769  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.DIRECTORIES);
770  break;
771  case TYPE_FILTER_VALUE_ALL:
772  case TYPE_FILTER_VALUE_FILES_AND_DIRS: //converts legacy xmls to current metaCondition terms
773  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.ALL);
774  break;
775  default:
776  logger.log(Level.SEVERE, "Found {0} " + TYPE_FILTER_ATTR + " attribute with unrecognized value ''{0}'', ignoring malformed rule definition", conditionAttribute); // NON-NLS
777  // Malformed attribute.
778 
779  throw new FilesSetsManager.FilesSetsManagerException(
780  Bundle.InterestingItemsFilesSetSettings_readMetaTypeCondition_malformedXml(
781  conditionAttribute, readRuleName(ruleElement)));
782  }
783  }
784  }
785  if (metaCondition == null) {
786  // Accept TSK Framework FilesSet definitions,
787  // default to files.
788  metaCondition = new MetaTypeCondition(MetaTypeCondition.Type.FILES);
789  }
790  return metaCondition;
791  }
792 }

Copyright © 2012-2021 Basis Technology. Generated on: Tue Jan 19 2021
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.