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);
308 String content = elem.getTextContent();
309 FilesSet.Rule.FullNameCondition nameCondition;
311 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
313 if (pattern != null) {
314 nameCondition =
new FilesSet.Rule.FullNameCondition(pattern);
316 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
NAME_RULE_TAG +
" regex, ignoring malformed '{0}' rule definition", ruleName);
320 for (String illegalChar : illegalFileNameChars) {
321 if (content.contains(illegalChar)) {
322 logger.log(Level.SEVERE,
FilesSetXML.
NAME_RULE_TAG +
" content has illegal chars, ignoring malformed '{0}' rule definition",
new Object[]{FilesSetXML.NAME_RULE_TAG, ruleName});
326 nameCondition =
new FilesSet.Rule.FullNameCondition(content);
331 if (metaTypeCondition == null) {
338 FilesSet.Rule.ParentPathCondition pathCondition = null;
342 if (pathCondition == null) {
348 return new FilesSet.Rule(ruleName, nameCondition, metaTypeCondition, pathCondition, null, null);
366 String content = elem.getTextContent();
367 FilesSet.Rule.ExtensionCondition extCondition;
369 if ((!regex.isEmpty() && regex.equalsIgnoreCase(
"true")) || content.contains(
"*")) {
371 if (pattern != null) {
372 extCondition =
new FilesSet.Rule.ExtensionCondition(pattern);
378 for (String illegalChar : illegalFileNameChars) {
379 if (content.contains(illegalChar)) {
380 logger.log(Level.SEVERE,
"{0} content has illegal chars, ignoring malformed {1} rule definition", ruleName);
384 extCondition =
new FilesSet.Rule.ExtensionCondition(content);
389 FilesSet.Rule.MetaTypeCondition metaTypeCondition = null;
392 if (metaTypeCondition == null) {
397 metaTypeCondition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
402 FilesSet.Rule.ParentPathCondition pathCondition = null;
406 if (pathCondition == null) {
412 return new FilesSet.Rule(ruleName, extCondition, metaTypeCondition, pathCondition, null, null);
437 return Pattern.compile(regex);
438 }
catch (PatternSyntaxException ex) {
439 logger.log(Level.SEVERE,
"Error compiling rule regex: " + ex.getMessage(), ex);
454 FilesSet.Rule.MetaTypeCondition condition = null;
456 if (!conditionAttribute.isEmpty()) {
457 switch (conditionAttribute) {
459 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
462 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.DIRECTORIES);
465 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES_AND_DIRECTORIES);
468 logger.log(Level.SEVERE,
"Found {0} " +
FilesSetXML.
TYPE_FILTER_ATTR +
" attribute with unrecognized value ''{0}'', ignoring malformed rule definition", conditionAttribute);
474 condition =
new FilesSet.Rule.MetaTypeCondition(FilesSet.Rule.MetaTypeCondition.Type.FILES);
488 FilesSet.Rule.ParentPathCondition condition = null;
491 if (!pathRegex.isEmpty() && path.isEmpty()) {
493 Pattern pattern = Pattern.compile(pathRegex);
494 condition =
new FilesSet.Rule.ParentPathCondition(pattern);
495 }
catch (PatternSyntaxException ex) {
496 logger.log(Level.SEVERE,
"Error compiling " +
FilesSetXML.
PATH_REGEX_ATTR +
" regex, ignoring malformed path condition definition", ex);
498 }
else if (!path.isEmpty() && pathRegex.isEmpty()) {
499 condition =
new FilesSet.Rule.ParentPathCondition(path);
516 static boolean writeDefinitionsFile(String filePath, Map<String, FilesSet> interestingFilesSets)
throws InterestingItemDefsManagerException {
517 try (NbObjectOutputStream out =
new NbObjectOutputStream(
new FileOutputStream(filePath))) {
518 out.writeObject(
new InterestingItemsFilesSetSettings(interestingFilesSets));
519 }
catch (IOException ex) {
520 throw new InterestingItemDefsManagerException(String.format(
"Failed to write settings to %s", filePath), ex);
526 static class InterestingItemDefsManagerException
extends Exception {
528 InterestingItemDefsManagerException() {
532 InterestingItemDefsManagerException(String message) {
536 InterestingItemDefsManagerException(String message, Throwable cause) {
537 super(message, cause);
540 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