19 package org.sleuthkit.autopsy.modules.interestingitems;
22 import java.io.FileInputStream;
23 import java.io.FileOutputStream;
24 import java.io.IOException;
25 import java.util.ArrayList;
26 import java.util.Arrays;
27 import java.util.Collections;
28 import java.util.HashMap;
29 import java.util.List;
31 import java.util.Observable;
32 import java.util.logging.Level;
33 import java.util.regex.Pattern;
34 import java.util.regex.PatternSyntaxException;
35 import org.openide.util.io.NbObjectInputStream;
36 import org.openide.util.io.NbObjectOutputStream;
40 import org.w3c.dom.Document;
41 import org.w3c.dom.Element;
42 import org.w3c.dom.NodeList;
50 final class InterestingItemDefsManager
extends Observable {
52 private static final List<String> ILLEGAL_FILE_NAME_CHARS = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(
"\\",
"/",
":",
"*",
"?",
"\"",
"<",
">")));
53 private static final List<String> ILLEGAL_FILE_PATH_CHARS = Collections.unmodifiableList(
new ArrayList<>(Arrays.asList(
"\\",
":",
"*",
"?",
"\"",
"<",
">")));
54 private static final String LEGACY_FILES_SET_DEFS_FILE_NAME =
"InterestingFilesSetDefs.xml";
55 private static final String INTERESTING_FILES_SET_DEFS_SERIALIZATION_NAME =
"InterestingFileSets.settings";
56 private static final String INTERESTING_FILES_SET_DEFS_SERIALIZATION_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + INTERESTING_FILES_SET_DEFS_SERIALIZATION_NAME;
57 private static final String LEGACY_FILE_SET_DEFS_PATH = PlatformUtil.getUserConfigDirectory() + File.separator + LEGACY_FILES_SET_DEFS_FILE_NAME;
58 private static InterestingItemDefsManager instance;
63 synchronized static InterestingItemDefsManager getInstance() {
64 if (instance == null) {
65 instance =
new InterestingItemDefsManager();
75 static List<String> getIllegalFileNameChars() {
76 return InterestingItemDefsManager.ILLEGAL_FILE_NAME_CHARS;
85 static List<String> getIllegalFilePathChars() {
86 return InterestingItemDefsManager.ILLEGAL_FILE_PATH_CHARS;
95 synchronized Map<String, FilesSet> getInterestingFilesSets() throws InterestingItemDefsManagerException {
96 return FilesSetXML.readDefinitionsFile(LEGACY_FILE_SET_DEFS_PATH);
106 synchronized void setInterestingFilesSets(Map<String, FilesSet> filesSets)
throws InterestingItemDefsManagerException {
107 FilesSetXML.writeDefinitionsFile(INTERESTING_FILES_SET_DEFS_SERIALIZATION_PATH, filesSets);
109 this.notifyObservers();
153 static Map<String, FilesSet> readDefinitionsFile(String filePath)
throws InterestingItemDefsManagerException {
156 if (!filesSets.isEmpty()) {
160 File defsFile =
new File(filePath);
161 if (!defsFile.exists()) {
166 if (!defsFile.canRead()) {
167 logger.log(Level.SEVERE,
"Interesting file sets definition file at {0} exists, but cannot be read", filePath);
174 logger.log(Level.SEVERE,
"Failed to parse interesting file sets definition file at {0}", filePath);
179 Element root = doc.getDocumentElement();
181 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});
186 NodeList setElems = root.getElementsByTagName(FILE_SET_TAG);
187 for (
int i = 0; i < setElems.getLength(); ++i) {
188 readFilesSet((Element) setElems.item(i), filesSets, filePath);
202 String filePath = INTERESTING_FILES_SET_DEFS_SERIALIZATION_PATH;
203 File fileSetFile =
new File(filePath);
204 if (fileSetFile.exists()) {
206 try (NbObjectInputStream in =
new NbObjectInputStream(
new FileInputStream(filePath))) {
207 InterestingItemsFilesSetSettings filesSetsSettings = (InterestingItemsFilesSetSettings) in.readObject();
208 return filesSetsSettings.getFilesSets();
210 }
catch (IOException | ClassNotFoundException ex) {
211 throw new InterestingItemDefsManagerException(String.format(
"Failed to read settings from %s", filePath), ex);
214 return new HashMap<String, FilesSet>();
225 private static void readFilesSet(Element setElem, Map<String, FilesSet> filesSets, String filePath) {
228 if (setName.isEmpty()) {
229 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});
232 if (filesSets.containsKey(setName)) {
233 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});
243 boolean ignoreKnownFiles =
false;
244 if (!ignoreKnown.isEmpty()) {
245 ignoreKnownFiles = Boolean.parseBoolean(ignoreKnown);
250 Map<String, FilesSet.Rule> rules =
new HashMap<>();
252 for (
int j = 0; j < nameRuleElems.getLength(); ++j) {
253 Element elem = (Element) nameRuleElems.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});
270 for (
int j = 0; j < extRuleElems.getLength(); ++j) {
271 Element elem = (Element) extRuleElems.item(j);
274 if (!rules.containsKey(rule.getUuid())) {
275 rules.put(rule.getUuid(), rule);
277 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});
281 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});
289 FilesSet set =
new FilesSet(setName, description, ignoreKnownFiles, rules);
290 filesSets.put(set.getName(), set);
310 String content = elem.getTextContent();
311 FilesSet.Rule.FullNameCondition nameCondition;
313 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
315 if (pattern != null) {
316 nameCondition =
new FilesSet.Rule.FullNameCondition(pattern);
318 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
NAME_RULE_TAG +
" regex, ignoring malformed '{0}' rule definition", ruleName);
322 for (String illegalChar : illegalFileNameChars) {
323 if (content.contains(illegalChar)) {
324 logger.log(Level.SEVERE,
FilesSetXML.
NAME_RULE_TAG +
" content has illegal chars, ignoring malformed '{0}' rule definition",
new Object[]{FilesSetXML.NAME_RULE_TAG, ruleName});
328 nameCondition =
new FilesSet.Rule.FullNameCondition(content);
333 if (metaTypeCondition == null) {
340 FilesSet.Rule.ParentPathCondition pathCondition = null;
344 if (pathCondition == null) {
350 return new FilesSet.Rule(ruleName, nameCondition, metaTypeCondition, pathCondition, null, null);
368 String content = elem.getTextContent();
369 FilesSet.Rule.ExtensionCondition extCondition;
371 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
373 if (pattern != null) {
374 extCondition =
new FilesSet.Rule.ExtensionCondition(pattern);
380 for (String illegalChar : illegalFileNameChars) {
381 if (content.contains(illegalChar)) {
382 logger.log(Level.SEVERE,
"{0} content has illegal chars, ignoring malformed {1} rule definition", ruleName);
386 extCondition =
new FilesSet.Rule.ExtensionCondition(content);
391 FilesSet.Rule.MetaTypeCondition metaTypeCondition = null;
394 if (metaTypeCondition == null) {
399 metaTypeCondition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
404 FilesSet.Rule.ParentPathCondition pathCondition = null;
408 if (pathCondition == null) {
414 return new FilesSet.Rule(ruleName, extCondition, metaTypeCondition, pathCondition, null, null);
439 return Pattern.compile(regex);
440 }
catch (PatternSyntaxException ex) {
441 logger.log(Level.SEVERE,
"Error compiling rule regex: " + ex.getMessage(), ex);
456 FilesSet.Rule.MetaTypeCondition condition = null;
458 if (!conditionAttribute.isEmpty()) {
459 switch (conditionAttribute) {
461 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
464 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.DIRECTORIES);
467 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES_AND_DIRECTORIES);
470 logger.log(Level.SEVERE,
"Found {0} " +
FilesSetXML.
TYPE_FILTER_ATTR +
" attribute with unrecognized value ''{0}'', ignoring malformed rule definition", conditionAttribute);
476 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
490 FilesSet.Rule.ParentPathCondition condition = null;
493 if (!pathRegex.isEmpty() && path.isEmpty()) {
495 Pattern pattern = Pattern.compile(pathRegex);
496 condition =
new FilesSet.Rule.ParentPathCondition(pattern);
497 }
catch (PatternSyntaxException ex) {
498 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
PATH_REGEX_ATTR +
" regex, ignoring malformed path condition definition", ex);
500 }
else if (!path.isEmpty() && pathRegex.isEmpty()) {
501 condition =
new FilesSet.Rule.ParentPathCondition(path);
518 static boolean writeDefinitionsFile(String filePath, Map<String, FilesSet> interestingFilesSets)
throws InterestingItemDefsManagerException {
519 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(filePath))) {
520 out.writeObject(
new InterestingItemsFilesSetSettings(interestingFilesSets));
521 }
catch (IOException ex) {
522 throw new InterestingItemDefsManagerException(String.format(
"Failed to write settings to %s", filePath), ex);
528 static class InterestingItemDefsManagerException
extends Exception {
530 InterestingItemDefsManagerException() {
534 InterestingItemDefsManagerException(String message) {
538 InterestingItemDefsManagerException(String message, Throwable cause) {
539 super(message, cause);
542 InterestingItemDefsManagerException(Throwable cause) {
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 FilesSet.Rule.MetaTypeCondition readMetaTypeCondition(Element ruleElement)
static final String NAME_ATTR
static final String PATH_REGEX_ATTR
static final String XML_ENCODING
static Map< String, FilesSet > readSerializedDefinitions()
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 final String FILE_SETS_ROOT_TAG
static final String EXTENSION_RULE_TAG
static final String FILE_SET_TAG
static final List< String > illegalFileNameChars
synchronized static Logger getLogger(String name)
static final String NAME_RULE_TAG
static FilesSet.Rule.ParentPathCondition readPathCondition(Element ruleElement)
static final String UNNAMED_LEGACY_RULE_PREFIX
static final String RULE_UUID_ATTR