Autopsy 4.22.1
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 */
19package org.sleuthkit.autopsy.modules.interestingitems;
20
21import java.io.File;
22import java.io.FileInputStream;
23import java.io.FileOutputStream;
24import java.io.IOException;
25import java.io.Serializable;
26import java.nio.file.Path;
27import java.nio.file.Paths;
28import java.util.Arrays;
29import java.util.Collection;
30import java.util.HashMap;
31import java.util.List;
32import java.util.Map;
33import java.util.logging.Level;
34import java.util.regex.Pattern;
35import java.util.regex.PatternSyntaxException;
36import javax.xml.parsers.DocumentBuilder;
37import javax.xml.parsers.DocumentBuilderFactory;
38import javax.xml.parsers.ParserConfigurationException;
39import org.apache.commons.lang.StringUtils;
40import static org.openide.util.NbBundle.Messages;
41import org.openide.util.io.NbObjectInputStream;
42import org.openide.util.io.NbObjectOutputStream;
43import org.sleuthkit.autopsy.coreutils.Logger;
44import org.sleuthkit.autopsy.coreutils.PlatformUtil;
45import org.sleuthkit.autopsy.coreutils.XMLUtil;
46import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.FileNameCondition;
47import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.FileSizeCondition;
48import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MetaTypeCondition;
49import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.MimeTypeCondition;
50import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.ParentPathCondition;
51import org.sleuthkit.autopsy.modules.interestingitems.FilesSet.Rule.DateCondition;
52import org.sleuthkit.autopsy.modules.interestingitems.FilesSetsManager.FilesSetsManagerException;
53import org.w3c.dom.Document;
54import org.w3c.dom.Element;
55import org.w3c.dom.NodeList;
56import java.util.Comparator;
57import java.util.function.Function;
58import java.util.stream.Collectors;
59
60class 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-2024 Sleuth Kit Labs. Generated on:
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.