Source code for plaso.filters.parser_filter

# -*- coding: utf-8 -*-
"""Helper for parser and plugin filter expressions."""


[docs] class ParserFilterExpressionHelper(object): """Helper for parser and plugin filter expressions. A parser filter expression is a comma separated value string that denotes which parsers and plugins should be used. Each element can contain either: * The name of a preset (case sensitive), which is a predefined list of parsers and/or plugins (see data/presets.yaml for the default presets). * The name of a parser (case insensitive), for example 'msiecf'. * The name of a plugin, prefixed with the parser name and a '/', for example 'sqlite/chrome_history'. If the element begins with an exclamation mark ('!') the item will be excluded from the set of enabled parsers and plugins, otherwise the element will be included. """ def _GetParserAndPluginsList(self, parsers_and_plugins): """Flattens the parsers and plugins dictionary into a list. Args: parsers_and_plugins (dict[str, set[str]]): parsers and plugins. Returns: list[str]: alphabetically sorted list of the parsers and plugins. """ parser_filters = [] for parser_name, plugins in sorted(parsers_and_plugins.items()): for plugin_name in sorted(plugins): if plugin_name == '*': parser_filters.append(parser_name) else: parser_filters.append('/'.join([parser_name, plugin_name])) return parser_filters def _JoinExpression(self, excludes, includes): """Creates an expression string of the excluded and included parsers. Note that exclusion takes precedence over inclusion. Args: excludes (dict[str, set[str]]): excluded parsers and plugins. includes (dict[str, set[str]]): included parsers and plugins. Returns: str: a parser filter expression. A parser filter expression is a comma separated value string that denotes which parsers should be used. Each element can contain either: * The name of a parser (case insensitive), for example 'msiecf'. * The name of a plugin, prefixed with the parser name and a '/', for example 'sqlite/chrome_history'. If the element begins with an exclamation mark ('!') the item will be excluded from the set of enabled parsers and plugins, otherwise the element will be included. Raises: RuntimeError: if a specific plugin is excluded but no corresponding parser is included. """ excluded_parsers_and_plugins = self._GetParserAndPluginsList(excludes) included_parsers_and_plugins = self._GetParserAndPluginsList(includes) # Note that below set comprehension is used to determine the set of # excluded and included parsers. excluded_parsers = { name for name, plugins in excludes.items() if plugins != set(['*'])} included_parsers = {name for name, plugins in includes.items() if plugins} missing_parser_filters = excluded_parsers.difference(included_parsers) if missing_parser_filters: missing_parser_filters = self._GetParserAndPluginsList({ name: excludes[name] for name in missing_parser_filters}) raise RuntimeError(( 'Parser filters: {0:s} defined to be excluded but no corresponding ' 'include expression').format(','.join(missing_parser_filters))) overlapping_parser_filters = set(included_parsers_and_plugins).intersection( set(excluded_parsers_and_plugins)) if overlapping_parser_filters: included_parsers_and_plugins = sorted( set(included_parsers_and_plugins) - overlapping_parser_filters) parser_filters = [ '!{0:s}'.format(parser_filter) for parser_filter in excluded_parsers_and_plugins] parser_filters.extend(included_parsers_and_plugins) return ','.join(parser_filters) def _ExpandPreset(self, presets_manager, preset_name, parsers_and_plugins): """Expands a preset in the parsers and plugins. This functions replaces the preset in parsers_and_plugins with the parser and plugin or preset names defined by the preset. Args: presets_manager (ParserPresetsManager): a parser preset manager, that is used to resolve which parsers and/or plugins are defined by presets. preset_name (str): name of the preset to expand. parsers_and_plugins (dict[str, set[str]]): parsers, plugins and presets. Raises: RuntimeError: if the plugins list of a preset in parsers_and_plugins, contains plugin definitions other than '*'. """ if preset_name not in parsers_and_plugins: return plugins = parsers_and_plugins.get(preset_name, None) if plugins != set(['*']): raise RuntimeError(( '{0:s} cannot be used as a preset name and plugin name at ' 'same time.').format(preset_name)) del parsers_and_plugins[preset_name] for parser_filter in presets_manager.GetParsersByPreset(preset_name): parser, _, plugin = parser_filter.partition('/') if not plugin: plugin = '*' parsers_and_plugins.setdefault(parser, set()) parsers_and_plugins[parser].add(plugin) def _ExpandPresets(self, presets_manager, preset_names, parsers_and_plugins): """Expands the presets in the parsers and plugins. This functions replaces the presets in parsers_and_plugins with the parser and plugin or preset names defined by the presets. Args: presets_manager (ParserPresetsManager): a parser preset manager, that is used to resolve which parsers and/or plugins are defined by presets. preset_names (set[str]): names of the presets defined by the presets manager. parsers_and_plugins (dict[str, set[str]]): parsers, plugins and presets. """ for preset_name in preset_names: self._ExpandPreset(presets_manager, preset_name, parsers_and_plugins)
[docs] def ExpandPresets(self, presets_manager, expression): """Expands all presets in a parser filter expression. Args: presets_manager (ParserPresetsManager): a parser preset manager, that is used to resolve which parsers and/or plugins are defined by presets. expression (str): parser filter expression, where an empty expression represents all parsers and plugins. A parser filter expression is a comma separated value string that denotes which parsers and plugins should be used. Each element can be either: * The name of a preset (case sensitive), which is a predefined list of parsers and/or plugins (see data/presets.yaml for the default presets). * The name of a parser (case insensitive), for example 'msiecf'. * The name of a plugin, prefixed with the parser name and a '/', for example 'sqlite/chrome_history'. If the element begins with an exclamation mark ('!') the item will be excluded from the set of enabled parsers and plugins, otherwise the element will be included. Returns: str: a parser filter expression where presets have been expanded or None to represent all parsers and plugins. """ if not expression: return None preset_names = set(presets_manager.GetNames()) excludes, includes = self.SplitExpression(expression) while set(excludes.keys()).intersection(preset_names): self._ExpandPresets(presets_manager, preset_names, excludes) while set(includes.keys()).intersection(preset_names): self._ExpandPresets(presets_manager, preset_names, includes) return self._JoinExpression(excludes, includes)
[docs] def SplitExpression(self, expression): """Determines the excluded and included elements in an expression string. This method will not expand presets, and preset names are treated like parser names. Args: expression (str): parser filter expression. A parser filter expression is a comma separated value string that denotes which parsers and plugins should be used. Each element can be either: * The name of a preset (case sensitive), which is a predefined list of parsers and/or plugins (see data/presets.yaml for the default presets). * The name of a parser (case insensitive), for example 'msiecf'. * The name of a plugin, prefixed with the parser name and a '/', for example 'sqlite/chrome_history'. If the element begins with an exclamation mark ('!') the item will be excluded from the set of enabled parsers and plugins, otherwise the element will be included. Returns: tuple: containing: excludes (dict[str, set[str]]): excluded presets, plugins and presets. Dictionary keys are preset and/or parser names, and values are sets containing plugin names to enable for a parser or an asterisk character ('*') to represent all plugins, or that no specific plugins were specified. includes (dict[str, set[str]]): included presets, parsers and plugins. Dictionary keys are preset and/or parser names, and values are sets containing plugin names to enable for a parser or an asterisk character ('*') to represent all plugins, or that no specific plugins were specified. """ if not expression: return {}, {} excludes = {} includes = {} for expression_element in expression.split(','): expression_element = expression_element.strip() if not expression_element: continue expression_element = expression_element.lower() if expression_element.startswith('!'): expression_element = expression_element[1:] parsers_and_plugins = excludes else: parsers_and_plugins = includes parser, _, plugin = expression_element.partition('/') if not plugin: plugin = '*' parsers_and_plugins.setdefault(parser, set()) parsers_and_plugins[parser].add(plugin) return excludes, includes