19 package org.sleuthkit.autopsy.modules.interestingitems;
22 import java.util.ArrayList;
23 import java.util.Arrays;
24 import java.util.Collections;
25 import java.util.HashMap;
26 import java.util.List;
28 import java.util.Observable;
29 import java.util.logging.Level;
30 import java.util.regex.Pattern;
31 import java.util.regex.PatternSyntaxException;
32 import javax.xml.parsers.DocumentBuilder;
33 import javax.xml.parsers.DocumentBuilderFactory;
34 import javax.xml.parsers.ParserConfigurationException;
38 import org.w3c.dom.Document;
39 import org.w3c.dom.Element;
40 import org.w3c.dom.NodeList;
48 final class InterestingItemDefsManager
extends Observable {
50 private static final List<String> ILLEGAL_FILE_NAME_CHARS = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(
"\\",
"/",
":",
"*",
"?",
"\"",
"<",
">")));
51 private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(
"\\",
":",
"*",
"?",
"\"",
"<",
">")));
52 private static final String INTERESTING_FILES_SET_DEFS_FILE_NAME =
"InterestingFilesSetDefs.xml";
53 private static final String DEFAULT_FILE_SET_DEFS_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + INTERESTING_FILES_SET_DEFS_FILE_NAME;
54 private static InterestingItemDefsManager instance;
59 synchronized static InterestingItemDefsManager getInstance() {
60 if (instance == null) {
61 instance =
new InterestingItemDefsManager();
71 static List<String> getIllegalFileNameChars() {
72 return InterestingItemDefsManager.ILLEGAL_FILE_NAME_CHARS;
80 static List<String> getIllegalFilePathChars() {
81 return InterestingItemDefsManager.ILLEGAL_FILE_PATH_CHARS;
90 synchronized Map<String, FilesSet> getInterestingFilesSets() {
91 return FilesSetXML.readDefinitionsFile(DEFAULT_FILE_SET_DEFS_PATH);
101 synchronized void setInterestingFilesSets(Map<String, FilesSet> filesSets) {
102 FilesSetXML.writeDefinitionsFile(DEFAULT_FILE_SET_DEFS_PATH, filesSets);
104 this.notifyObservers();
162 static Map<String, FilesSet> readDefinitionsFile(String filePath) {
163 Map<String, FilesSet> filesSets =
new HashMap<>();
166 File defsFile =
new File(filePath);
167 if (!defsFile.exists()) {
172 if (!defsFile.canRead()) {
173 logger.log(Level.SEVERE,
"Interesting file sets definition file at {0} exists, but cannot be read", filePath);
180 logger.log(Level.SEVERE,
"Failed to parse interesting file sets definition file at {0}", filePath);
185 Element root = doc.getDocumentElement();
187 logger.log(Level.SEVERE,
"Failed to get root {0} element tag of interesting file sets definition file at {1}",
new Object[]{FilesSetXML.FILE_SETS_ROOT_TAG, filePath});
192 NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
193 for (
int i = 0; i < setElems.getLength(); ++i) {
194 readFilesSet((Element) setElems.item(i), filesSets, filePath);
207 private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) {
210 if (setName.isEmpty()) {
211 logger.log(Level.SEVERE,
"Found {0} element without required {1} attribute, ignoring malformed file set definition in interesting file sets definition file at {2}",
new Object[]{FilesSetXML.FILE_SET_TAG, FilesSetXML.NAME_ATTR, filePath});
214 if (filesSets.containsKey(setName)) {
215 logger.log(Level.SEVERE,
"Found duplicate definition of set named {0} in interesting file sets definition file at {1}, discarding duplicate set",
new Object[]{setName, filePath});
225 boolean ignoreKnownFiles =
false;
226 if (!ignoreKnown.isEmpty()) {
227 ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
232 Map<String, FilesSet.Rule> rules =
new HashMap<>();
234 for (
int j = 0; j < nameRuleElems.getLength(); ++j) {
235 Element elem = (Element) nameRuleElems.item(j);
238 if (!rules.containsKey(rule.getUuid())) {
239 rules.put(rule.getUuid(), rule);
241 logger.log(Level.SEVERE,
"Found duplicate rule {0} for set named {1} in interesting file sets definition file at {2}, discarding malformed set",
new Object[]{rule.getUuid(), setName, filePath});
245 logger.log(Level.SEVERE,
"Found malformed rule for set named {0} in interesting file sets definition file at {1}, discarding malformed set",
new Object[]{setName, filePath});
252 for (
int j = 0; j < extRuleElems.getLength(); ++j) {
253 Element elem = (Element) extRuleElems.item(j);
256 if (!rules.containsKey(rule.getUuid())) {
257 rules.put(rule.getUuid(), rule);
259 logger.log(Level.SEVERE,
"Found duplicate rule {0} for set named {1} in interesting file sets definition file at {2}, discarding malformed set",
new Object[]{rule.getUuid(), setName, filePath});
263 logger.log(Level.SEVERE,
"Found malformed rule for set named {0} in interesting file sets definition file at {1}, discarding malformed set",
new Object[]{setName, filePath});
271 FilesSet set =
new FilesSet(setName, description, ignoreKnownFiles, rules);
272 filesSets.put(set.getName(), set);
291 String content = elem.getTextContent();
292 FilesSet.Rule.FullNameFilter nameFilter;
294 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
296 if (pattern != null) {
297 nameFilter =
new FilesSet.Rule.FullNameFilter(pattern);
299 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
NAME_RULE_TAG +
" regex, ignoring malformed '{0}' rule definition", ruleName);
303 for (String illegalChar : illegalFileNameChars) {
304 if (content.contains(illegalChar)) {
305 logger.log(Level.SEVERE,
FilesSetXML.
NAME_RULE_TAG +
" content has illegal chars, ignoring malformed '{0}' rule definition",
new Object[]{FilesSetXML.NAME_RULE_TAG, ruleName});
309 nameFilter =
new FilesSet.Rule.FullNameFilter(content);
314 if (metaTypeFilter == null) {
321 FilesSet.Rule.ParentPathFilter pathFilter = null;
325 if (pathFilter == null) {
331 return new FilesSet.Rule(ruleName, nameFilter, metaTypeFilter, pathFilter);
348 String content = elem.getTextContent();
349 FilesSet.Rule.ExtensionFilter extFilter;
351 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
353 if (pattern != null) {
354 extFilter =
new FilesSet.Rule.ExtensionFilter(pattern);
360 for (String illegalChar : illegalFileNameChars) {
361 if (content.contains(illegalChar)) {
362 logger.log(Level.SEVERE,
"{0} content has illegal chars, ignoring malformed {1} rule definition", ruleName);
366 extFilter =
new FilesSet.Rule.ExtensionFilter(content);
371 FilesSet.Rule.MetaTypeFilter metaTypeFilter = null;
374 if (metaTypeFilter == null) {
379 metaTypeFilter =
new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
384 FilesSet.Rule.ParentPathFilter pathFilter = null;
388 if (pathFilter == null) {
394 return new FilesSet.Rule(ruleName, extFilter, metaTypeFilter, pathFilter);
417 return Pattern.compile(regex);
418 }
catch (PatternSyntaxException ex) {
419 logger.log(Level.SEVERE,
"Error compiling rule regex: " + ex.getMessage(), ex);
432 FilesSet.Rule.MetaTypeFilter filter = null;
434 if (!filterAttribute.isEmpty()) {
435 switch (filterAttribute) {
437 filter =
new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
440 filter =
new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.DIRECTORIES);
443 filter =
new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES_AND_DIRECTORIES);
446 logger.log(Level.SEVERE,
"Found {0} " +
FilesSetXML.
TYPE_FILTER_ATTR +
" attribute with unrecognized value ''{0}'', ignoring malformed rule definition", filterAttribute);
452 filter =
new FilesSet.Rule.MetaTypeFilter(FilesSet.Rule.MetaTypeFilter.Type.FILES);
464 private static FilesSet.Rule.ParentPathFilter
readPathFilter(Element ruleElement) {
465 FilesSet.Rule.ParentPathFilter filter = null;
468 if (!pathRegex.isEmpty() && path.isEmpty()) {
470 Pattern pattern = Pattern.compile(pathRegex);
471 filter =
new FilesSet.Rule.ParentPathFilter(pattern);
472 }
catch (PatternSyntaxException ex) {
473 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
PATH_REGEX_ATTR +
" regex, ignoring malformed path filter definition", ex);
475 }
else if (!path.isEmpty() && pathRegex.isEmpty()) {
476 filter =
new FilesSet.Rule.ParentPathFilter(path);
492 static boolean writeDefinitionsFile(String filePath, Map<String, FilesSet> interestingFilesSets) {
493 DocumentBuilderFactory docBuilderFactory = DocumentBuilderFactory.newInstance();
496 DocumentBuilder docBuilder = docBuilderFactory.newDocumentBuilder();
497 Document doc = docBuilder.newDocument();
499 doc.appendChild(rootElement);
502 for (FilesSet set : interestingFilesSets.values()) {
510 for (FilesSet.Rule rule : set.getRules().values()) {
513 FilesSet.Rule.FileNameFilter nameFilter = rule.getFileNameFilter();
515 if (nameFilter instanceof FilesSet.Rule.FullNameFilter) {
518 ruleElement = doc.createElement(FilesSetXML.EXTENSION_RULE_TAG);
523 ruleElement.setAttribute(FilesSetXML.NAME_ATTR, rule.getName());
526 ruleElement.setAttribute(FilesSetXML.REGEX_ATTR, Boolean.toString(nameFilter.isRegex()));
529 FilesSet.Rule.MetaTypeFilter typeFilter = rule.getMetaTypeFilter();
530 switch (typeFilter.getMetaType()) {
532 ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_FILES);
535 ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_DIRS);
538 ruleElement.setAttribute(FilesSetXML.TYPE_FILTER_ATTR, FilesSetXML.TYPE_FILTER_VALUE_FILES_AND_DIRS);
543 FilesSet.Rule.ParentPathFilter pathFilter = rule.getPathFilter();
544 if (pathFilter != null) {
545 if (pathFilter.isRegex()) {
546 ruleElement.setAttribute(FilesSetXML.PATH_REGEX_ATTR, pathFilter.getTextToMatch());
548 ruleElement.setAttribute(FilesSetXML.PATH_FILTER_ATTR, pathFilter.getTextToMatch());
553 ruleElement.setTextContent(nameFilter.getTextToMatch());
555 setElement.appendChild(ruleElement);
558 rootElement.appendChild(setElement);
563 return XMLUtil.saveDoc(FilesSetXML.class, filePath, XML_ENCODING, doc);
565 }
catch (ParserConfigurationException ex) {
566 logger.log(Level.SEVERE,
"Error writing interesting files definition file to " + filePath, ex);
static Pattern compileRegex(String regex)
static final String IGNORE_KNOWN_FILES_ATTR
static final String TYPE_FILTER_VALUE_FILES
static< T > Document loadDoc(Class< T > clazz, String xmlPath)
static int unnamedLegacyRuleCounter
static final String TYPE_FILTER_VALUE_DIRS
static String readRuleName(Element elem)
static final String TYPE_FILTER_ATTR
static final Logger logger
static final String DESC_ATTR
static FilesSet.Rule readFileExtensionRule(Element elem)
static final String NAME_ATTR
static final String PATH_REGEX_ATTR
static final String XML_ENCODING
static final String TYPE_FILTER_VALUE_FILES_AND_DIRS
static final String REGEX_ATTR
static FilesSet.Rule readFileNameRule(Element elem)
static void readFilesSet(Element setElem, Map< String, FilesSet > filesSets, String filePath)
static final String PATH_FILTER_ATTR
static FilesSet.Rule.ParentPathFilter readPathFilter(Element ruleElement)
static final String FILE_SETS_ROOT_TAG
static final String EXTENSION_RULE_TAG
static final String FILE_SET_TAG
static final List< String > illegalFileNameChars
static final String NAME_RULE_TAG
static FilesSet.Rule.MetaTypeFilter readMetaTypeFilter(Element ruleElement)
static final String UNNAMED_LEGACY_RULE_PREFIX
static final String RULE_UUID_ATTR
static Logger getLogger(String name)