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