From cfdf579ea441c2965615475dfcc82b2aa743328b Mon Sep 17 00:00:00 2001 From: Joachim Metz Date: Sat, 2 Jan 2021 12:18:56 +0100 Subject: [PATCH] Added support for custom formatter helpers #444 (#3377) --- data/formatters/browser.yaml | 21 ++++++ data/formatters/generic.yaml | 12 ++++ data/formatters/windows.yaml | 14 ++++ docs/sources/user/Output-and-formatting.md | 48 ++++++++++++-- plaso/formatters/chrome.py | 28 ++++---- plaso/formatters/chrome_preferences.py | 34 +++++++--- plaso/formatters/file_system.py | 44 +++++++------ plaso/formatters/firefox.py | 33 +++++++--- plaso/formatters/interface.py | 21 ++++-- plaso/formatters/manager.py | 26 ++++---- plaso/formatters/msiecf.py | 24 +++---- plaso/formatters/shell_items.py | 9 +-- plaso/formatters/winlnk.py | 13 ++-- plaso/formatters/winprefetch.py | 40 +++++++---- plaso/formatters/winreg.py | 9 +-- plaso/formatters/yaml_formatters_file.py | 28 ++++++++ tests/formatters/chrome.py | 37 ++++++++--- tests/formatters/chrome_preferences.py | 60 ++++++++++++++--- tests/formatters/file_system.py | 55 ++++++++++++---- tests/formatters/firefox.py | 40 ++++++++--- tests/formatters/msiecf.py | 50 +++++++++----- tests/formatters/shell_items.py | 32 ++++++--- tests/formatters/winlnk.py | 54 ++++++++++++--- tests/formatters/winprefetch.py | 66 +++++++++++++++++-- tests/formatters/winreg.py | 22 ++++--- .../olecf_plugins/automatic_destinations.py | 5 +- 26 files changed, 622 insertions(+), 203 deletions(-) diff --git a/data/formatters/browser.yaml b/data/formatters/browser.yaml index 5f04c1a14b..26773c44f3 100644 --- a/data/formatters/browser.yaml +++ b/data/formatters/browser.yaml @@ -76,6 +76,9 @@ boolean_helpers: - input_attribute: 'url_hidden' output_attribute: 'url_hidden_string' value_if_true: '(URL hidden)' +custom_helpers: +- identifier: 'chrome_history_typed_count' + output_attribute: 'url_typed_string' enumeration_helpers: - input_attribute: 'page_transition_type' output_attribute: 'page_transition' @@ -126,6 +129,11 @@ short_message: --- type: 'conditional' data_type: 'chrome:preferences:content_settings:exceptions' +custom_helpers: +- identifier: 'chrome_preferences_primary_url' + output_attribute: 'primary_url' +- identifier: 'chrome_preferences_secondary_url' + output_attribute: 'secondary_url' message: - 'Permission {permission}' - 'used by {primary_url}' @@ -253,6 +261,11 @@ short_message: '{title}' --- type: 'conditional' data_type: 'firefox:places:page_visited' +custom_helpers: +- identifier: 'firefox_history_typed_count' + output_attribute: 'url_typed_string' +- identifier: 'firefox_history_url_hidden' + output_attribute: 'url_hidden_string' enumeration_helpers: - input_attribute: 'visit_type' output_attribute: 'transition_string' @@ -290,6 +303,9 @@ boolean_helpers: - input_attribute: 'recovered' output_attribute: 'recovered_string' value_if_true: '[Recovered Entry]' +custom_helpers: +- identifier: 'msiecf_cached_path' + output_attribute: 'cached_file_path' message: - 'Cached file: {cached_file_path}' - 'Cached file size: {cached_file_size}' @@ -315,6 +331,11 @@ boolean_helpers: - input_attribute: 'recovered' output_attribute: 'recovered_string' value_if_true: '[Recovered Entry]' +custom_helpers: +- identifier: 'msiecf_cached_path' + output_attribute: 'cached_file_path' +- identifier: 'msiecf_http_headers' + output_attribute: 'http_headers' message: - 'Location: {url}' - 'Number of hits: {number_of_hits}' diff --git a/data/formatters/generic.yaml b/data/formatters/generic.yaml index 8e50b19798..cebaecf556 100644 --- a/data/formatters/generic.yaml +++ b/data/formatters/generic.yaml @@ -183,6 +183,11 @@ short_message: '{filename}' --- type: 'conditional' data_type: 'fs:ntfs:usn_change' +custom_helpers: +- identifier: 'ntfs_file_reference' + output_attribute: 'file_reference' +- identifier: 'ntfs_parent_file_reference' + output_attribute: 'parent_file_reference' flags_helpers: - input_attribute: 'update_reason_flags' output_attribute: 'update_reason' @@ -245,6 +250,13 @@ boolean_helpers: - input_attribute: 'is_allocated' output_attribute: 'unallocated' value_if_false: 'unallocated' +custom_helpers: +- identifier: 'ntfs_file_reference' + output_attribute: 'file_reference' +- identifier: 'ntfs_parent_file_reference' + output_attribute: 'parent_file_reference' +- identifier: 'ntfs_path_hints' + output_attribute: 'path_hints' enumeration_helpers: - input_attribute: 'attribute_type' output_attribute: 'attribute_name' diff --git a/data/formatters/windows.yaml b/data/formatters/windows.yaml index 9056f97e96..59e79975ed 100644 --- a/data/formatters/windows.yaml +++ b/data/formatters/windows.yaml @@ -161,6 +161,9 @@ short_message: --- type: 'conditional' data_type: 'windows:lnk:link' +custom_helpers: +- identifier: 'windows_shortcut_linked_path' + output_attribute: 'linked_path' message: - '[{description}]' - 'File size: {file_size}' @@ -224,6 +227,11 @@ short_message: --- type: 'conditional' data_type: 'windows:prefetch:execution' +custom_helpers: +- identifier: 'windows_prefetch_path_hints' + output_attribute: 'path_hints' +- identifier: 'windows_prefetch_volumes_string' + output_attribute: 'volumes_string' message: - 'Prefetch' - '[{executable}] was executed -' @@ -330,6 +338,9 @@ short_message: --- type: 'conditional' data_type: 'windows:registry:key_value' +custom_helpers: +- identifier: 'windows_registry_values' + output_attribute: 'values' message: - '[{key_path}]' - '{values}' @@ -637,6 +648,9 @@ short_message: '[{key_path}] {entries}' --- type: 'conditional' data_type: 'windows:shell_item:file_entry' +custom_helpers: +- identifier: 'shell_item_file_entry_name' + output_attribute: 'file_entry_name' message: - 'Name: {name}' - 'Long name: {long_name}' diff --git a/docs/sources/user/Output-and-formatting.md b/docs/sources/user/Output-and-formatting.md index 6bb3d52a18..d7f2b66ea4 100644 --- a/docs/sources/user/Output-and-formatting.md +++ b/docs/sources/user/Output-and-formatting.md @@ -96,6 +96,7 @@ An event formatter is defined as a set of attributes: * "data_type"; required event data type. * "boolean_helpers"; optional boolean helpers. +* "custom_helpers"; optional custom helpers. * "enumeration_helpers"; optional enumeration helpers. * "message"; required formatter message string, for a basic type, or list of messages string pieces, for a conditional type. * "separator"; optional conditional message string piece separator, the default is a single space. @@ -143,14 +144,42 @@ short_message: - '{path}' ``` -boolean helpers are defined as a set of attributes: +Boolean helpers are defined as a set of attributes: -* "input_attribute"; required name of the attribute which the value that needs to be mapped is read from. -* "output_attribute"; required name of the attribute which the mapped value is written to. +* "input_attribute"; required name of the attribute which the value is read from. +* "output_attribute"; required name of the attribute which the formatted value is written to. * "default_value"; optional default value if there is no corresponding mapping in "values". * "value_if_false"; optional output value if the boolean input value is False. * "value_if_true"; optional output value if the boolean input value is True. +#### Custom helpers + +Custom helpers can be defined to map a value of an event attribute to custom +formatting code. + +``` +type: 'conditional' +data_type: 'fs:stat:ntfs' +custom_helpers: +- identifier: 'ntfs_file_reference' + output_attribute: 'file_reference' +message: +- '{display_name}' +- 'File reference: {file_reference}' +short_message: +- '{filename}' +- '{file_reference}' +``` + +Here `ntfs_file_reference` references the `NTFSFileReferenceFormatterHelper`, +which is defined in `plaso/formatters/file_system.py`. + +Custom helpers are defined as a set of attributes: + +* "identifier"; required identifier of the custom format helper. +* "input_attribute"; optional name of the attribute which the value is read from. +* "output_attribute"; optional name of the attribute which the formatted value is written to. + #### Enumeration helpers Enumeration helpers can be defined to map a value of an event attribute to @@ -186,10 +215,10 @@ short_message: - '{description}' ``` -enumeration helpers are defined as a set of attributes: +Enumeration helpers are defined as a set of attributes: -* "input_attribute"; required name of the attribute which the value that needs to be mapped is read from. -* "output_attribute"; required name of the attribute which the mapped value is written to. +* "input_attribute"; required name of the attribute which the value is read from. +* "output_attribute"; required name of the attribute which the formatted value is written to. * "default_value"; optional default value if there is no corresponding mapping in "values". * "values"; required value mappings, contains key value pairs. @@ -241,6 +270,12 @@ short_message: - '{flag_values}' ``` +Flags helpers are defined as a set of attributes: + +* "input_attribute"; required name of the attribute which the value is read from. +* "output_attribute"; required name of the attribute which the formatted value is written to. +* "values"; required value mappings, contains key value pairs. + #### Change log * 20200227 Added support for formatter configuration files. @@ -248,3 +283,4 @@ short_message: * 20200904 Added support for flags helpers. * 20200916 Removed source types from formatters. * 20201220 Added support for boolean helpers. +* 20201227 Added support for custom helpers. diff --git a/plaso/formatters/chrome.py b/plaso/formatters/chrome.py index 84f7b30a3d..a375e5719f 100644 --- a/plaso/formatters/chrome.py +++ b/plaso/formatters/chrome.py @@ -7,10 +7,11 @@ from plaso.formatters import manager -class ChromePageVisitedFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Chrome page visited event values.""" +class ChromeHistoryTypedCountFormatterHelper( + interface.CustomEventFormatterHelper): + """Google Chrome history typed count formatter helper.""" - DATA_TYPE = 'chrome:history:page_visited' + IDENTIFIER = 'chrome_history_typed_count' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -18,16 +19,19 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - typed_count = event_values.get('typed_count', 0) - if typed_count == 0: - url_typed_string = '(URL not typed directly)' - elif typed_count == 1: - url_typed_string = '(URL typed {0:d} time)' - else: - url_typed_string = '(URL typed {0:d} times)' + typed_count = event_values.get('typed_count', None) + if typed_count is not None: + if typed_count == 0: + url_typed_string = '(URL not typed directly)' + elif typed_count == 1: + url_typed_string = '(URL typed 1 time)' + elif typed_count > 1: + url_typed_string = '(URL typed {0:d} times)'.format(typed_count) + else: + url_typed_string = typed_count - event_values['url_typed_string'] = url_typed_string + event_values['url_typed_string'] = url_typed_string manager.FormattersManager.RegisterEventFormatterHelper( - ChromePageVisitedFormatter) + ChromeHistoryTypedCountFormatterHelper) diff --git a/plaso/formatters/chrome_preferences.py b/plaso/formatters/chrome_preferences.py index 6095ca33cb..c1f6f5c45e 100644 --- a/plaso/formatters/chrome_preferences.py +++ b/plaso/formatters/chrome_preferences.py @@ -7,11 +7,11 @@ from plaso.formatters import manager -class ChromeContentSettingsExceptionsFormatter( +class ChromePreferencesPrimaryURLFormatterHelper( interface.CustomEventFormatterHelper): - """Custom formatter for Chrome content settings exceptions event values.""" + """Google Chrome preferences primary URL formatter helper.""" - DATA_TYPE = 'chrome:preferences:content_settings:exceptions' + IDENTIFIER = 'chrome_preferences_primary_url' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -19,7 +19,24 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - # There is apparently a bug, either in GURL.cc or + primary_url = event_values.get('primary_url', None) + if primary_url == '': + event_values['primary_url'] = 'local file' + + +class ChromePreferencesSecondaryURLFormatterHelper( + interface.CustomEventFormatterHelper): + """Google Chrome preferences secondary URL formatter helper.""" + + IDENTIFIER = 'chrome_preferences_secondary_url' + + def FormatEventValues(self, event_values): + """Formats event values using the helper. + + Args: + event_values (dict[str, object]): event values. + """ + # There appears to be an issue in either GURL.cc or # content_settings_pattern.cc where URLs with file:// scheme are stored in # the URL as an empty string, which is later detected as being Invalid, and # Chrome produces the following example logs: @@ -29,9 +46,6 @@ def FormatEventValues(self, event_values): # More research needed, could be related to https://crbug.com/132659 primary_url = event_values.get('primary_url', None) - if primary_url == '': - primary_url = 'local file' - secondary_url = event_values.get('secondary_url', None) if secondary_url == '': secondary_url = 'local file' @@ -39,9 +53,9 @@ def FormatEventValues(self, event_values): if secondary_url in (primary_url, '*'): secondary_url = None - event_values['primary_url'] = primary_url event_values['secondary_url'] = secondary_url -manager.FormattersManager.RegisterEventFormatterHelper( - ChromeContentSettingsExceptionsFormatter) +manager.FormattersManager.RegisterEventFormatterHelpers([ + ChromePreferencesPrimaryURLFormatterHelper, + ChromePreferencesSecondaryURLFormatterHelper]) diff --git a/plaso/formatters/file_system.py b/plaso/formatters/file_system.py index 202d02b10c..140d6bd203 100644 --- a/plaso/formatters/file_system.py +++ b/plaso/formatters/file_system.py @@ -7,10 +7,10 @@ from plaso.formatters import manager -class NTFSFileStatEventFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for NTFS file system stat event values.""" +class NTFSFileReferenceFormatterHelper(interface.CustomEventFormatterHelper): + """NTFS file reference formatter helper.""" - DATA_TYPE = 'fs:stat:ntfs' + IDENTIFIER = 'ntfs_file_reference' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -23,20 +23,29 @@ def FormatEventValues(self, event_values): event_values['file_reference'] = '{0:d}-{1:d}'.format( file_reference & 0xffffffffffff, file_reference >> 48) + +class NTFSParentFileReferenceFormatterHelper( + interface.CustomEventFormatterHelper): + """NTFS parent file reference formatter helper.""" + + IDENTIFIER = 'ntfs_parent_file_reference' + + def FormatEventValues(self, event_values): + """Formats event values using the helper. + + Args: + event_values (dict[str, object]): event values. + """ parent_file_reference = event_values.get('parent_file_reference', None) if parent_file_reference: event_values['parent_file_reference'] = '{0:d}-{1:d}'.format( parent_file_reference & 0xffffffffffff, parent_file_reference >> 48) - path_hints = event_values.get('path_hints', []) - if path_hints: - event_values['path_hints'] = ';'.join(path_hints) - -class NTFSUSNChangeEventFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for NTFS USN change event values.""" +class NTFSPathHintsFormatterHelper(interface.CustomEventFormatterHelper): + """NTFS path hints formatter helper.""" - DATA_TYPE = 'fs:ntfs:usn_change' + IDENTIFIER = 'ntfs_path_hints' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -44,16 +53,11 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - file_reference = event_values.get('file_reference', None) - if file_reference: - event_values['file_reference'] = '{0:d}-{1:d}'.format( - file_reference & 0xffffffffffff, file_reference >> 48) - - parent_file_reference = event_values.get('parent_file_reference', None) - if parent_file_reference: - event_values['parent_file_reference'] = '{0:d}-{1:d}'.format( - parent_file_reference & 0xffffffffffff, parent_file_reference >> 48) + path_hints = event_values.get('path_hints', None) + if path_hints: + event_values['path_hints'] = ';'.join(path_hints) manager.FormattersManager.RegisterEventFormatterHelpers([ - NTFSFileStatEventFormatter, NTFSUSNChangeEventFormatter]) + NTFSFileReferenceFormatterHelper, NTFSParentFileReferenceFormatterHelper, + NTFSPathHintsFormatterHelper]) diff --git a/plaso/formatters/firefox.py b/plaso/formatters/firefox.py index bb02dec62f..10cd670bb6 100644 --- a/plaso/formatters/firefox.py +++ b/plaso/formatters/firefox.py @@ -7,10 +7,11 @@ from plaso.formatters import manager -class FirefoxPageVisitFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Firefox page visited event values.""" +class FirefoxHistoryTypedCountFormatterHelper( + interface.CustomEventFormatterHelper): + """Mozilla Firefox history typed count formatter helper.""" - DATA_TYPE = 'firefox:places:page_visited' + IDENTIFIER = 'firefox_history_typed_count' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -18,10 +19,6 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - hidden = event_values.get('hidden', None) - if hidden == '1': - event_values['url_hidden_string'] = '(URL hidden)' - typed = event_values.get('typed', None) if typed == '1': url_typed_string = '(URL directly typed)' @@ -31,5 +28,23 @@ def FormatEventValues(self, event_values): event_values['url_typed_string'] = url_typed_string -manager.FormattersManager.RegisterEventFormatterHelper( - FirefoxPageVisitFormatter) +class FirefoxHistoryURLHiddenFormatterHelper( + interface.CustomEventFormatterHelper): + """Mozilla Firefox history URL hidden formatter helper.""" + + IDENTIFIER = 'firefox_history_url_hidden' + + def FormatEventValues(self, event_values): + """Formats event values using the helper. + + Args: + event_values (dict[str, object]): event values. + """ + hidden = event_values.get('hidden', None) + if hidden == '1': + event_values['url_hidden_string'] = '(URL hidden)' + + +manager.FormattersManager.RegisterEventFormatterHelpers([ + FirefoxHistoryTypedCountFormatterHelper, + FirefoxHistoryURLHiddenFormatterHelper]) diff --git a/plaso/formatters/interface.py b/plaso/formatters/interface.py index 1ebcbe15cf..6e8e3df10a 100644 --- a/plaso/formatters/interface.py +++ b/plaso/formatters/interface.py @@ -81,6 +81,7 @@ class CustomEventFormatterHelper(EventFormatterHelper): """Base class for a helper for custom formatting of event data.""" DATA_TYPE = '' + IDENTIFIER = '' @abc.abstractmethod def FormatEventValues(self, event_values): @@ -195,6 +196,7 @@ class EventFormatter(object): event object attribute is defined as {attribute_name}. Attributes: + custom_helpers (list[str]): identifiers of custom event formatter helpers. helpers (list[EventFormatterHelper]): event formatter helpers. """ @@ -208,10 +210,6 @@ class EventFormatter(object): FORMAT_STRING = '' FORMAT_STRING_SHORT = '' - # The source short and long strings. - SOURCE_SHORT = 'LOG' - SOURCE_LONG = '' - # The format string can be defined as: # {name}, {name:format}, {name!conversion}, {name!conversion:format} _FORMAT_STRING_ATTRIBUTE_NAME_RE = re.compile( @@ -221,6 +219,7 @@ def __init__(self): """Initializes an event formatter object.""" super(EventFormatter, self).__init__() self._format_string_attribute_names = None + self.custom_helpers = [] self.helpers = [] def _FormatMessage(self, format_string, event_values): @@ -309,6 +308,20 @@ def GetFormatStringAttributeNames(self): return set(self._format_string_attribute_names) + # pylint: disable=unused-argument + def AddCustomHelper( + self, identifier, input_attribute=None, output_attribute=None): + """Adds a custom event formatter helper. + + Args: + identifier (str): identifier. + input_attribute (Optional[str]): name of the attribute that contains + the input value. + output_attribute (Optional[str]): name of the attribute where the + output value should be stored. + """ + self.custom_helpers.append(identifier) + def AddHelper(self, helper): """Adds an event formatter helper. diff --git a/plaso/formatters/manager.py b/plaso/formatters/manager.py index acef1eb206..83615e5c95 100644 --- a/plaso/formatters/manager.py +++ b/plaso/formatters/manager.py @@ -33,13 +33,13 @@ def _ReadFormattersFile(cls, path): """ formatters_file = yaml_formatters_file.YAMLFormattersFile() for formatter in formatters_file.ReadFromFile(path): - data_type = formatter.DATA_TYPE.lower() - - custom_formatter_helper = cls._custom_formatter_helpers.get( - data_type, None) - if custom_formatter_helper: - formatter.AddHelper(custom_formatter_helper) + for identifier in formatter.custom_helpers: + custom_formatter_helper = cls._custom_formatter_helpers.get( + identifier, None) + if custom_formatter_helper: + formatter.AddHelper(custom_formatter_helper) + data_type = formatter.DATA_TYPE.lower() cls._formatters[data_type] = formatter @classmethod @@ -97,22 +97,22 @@ def RegisterEventFormatterHelper(cls, formatter_helper_class): """Registers a custom event formatter helper. The custom event formatter helpers are identified based on their lower - case data type. + case identifier. Args: formatter_helper_class (type): class of the custom event formatter helper. Raises: KeyError: if a custom formatter helper is already set for the - corresponding data type. + corresponding identifier. """ - data_type = formatter_helper_class.DATA_TYPE.lower() - if data_type in cls._custom_formatter_helpers: + identifier = formatter_helper_class.IDENTIFIER.lower() + if identifier in cls._custom_formatter_helpers: raise KeyError(( - 'Custom event formatter helper already set for data type: ' - '{0:s}.').format(formatter_helper_class.DATA_TYPE)) + 'Custom event formatter helper already set for identifier: ' + '{0:s}.').format(formatter_helper_class.IDENTIFIER)) - cls._custom_formatter_helpers[data_type] = formatter_helper_class() + cls._custom_formatter_helpers[identifier] = formatter_helper_class() @classmethod def RegisterEventFormatterHelpers(cls, formatter_helper_classes): diff --git a/plaso/formatters/msiecf.py b/plaso/formatters/msiecf.py index 4d5eeab877..f69a088d46 100644 --- a/plaso/formatters/msiecf.py +++ b/plaso/formatters/msiecf.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -"""Microsoft Internet Explorer (MSIE) custom event formatter helpers.""" +"""MSIE cache file custom event formatter helpers.""" from __future__ import unicode_literals @@ -7,10 +7,10 @@ from plaso.formatters import manager -class MsiecfLeakFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for MSIE cache file leak item event values.""" +class MSIECFCachedPathFormatterHelper(interface.CustomEventFormatterHelper): + """MSIE cache file cached path formatter helper.""" - DATA_TYPE = 'msiecf:leak' + IDENTIFIER = 'msiecf_cached_path' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -26,10 +26,11 @@ def FormatEventValues(self, event_values): event_values['cached_file_path'] = cached_file_path -class MsiecfUrlFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for MSIE cache file URL item event values.""" +class MSIECFHTTPHeadersventFormatterHelper( + interface.CustomEventFormatterHelper): + """MSIE cache file HTTP headers formatter helper.""" - DATA_TYPE = 'msiecf:url' + IDENTIFIER = 'msiecf_http_headers' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -37,17 +38,10 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - cached_file_path = event_values.get('cached_filename', None) - if cached_file_path: - cache_directory_name = event_values.get('cache_directory_name', None) - if cache_directory_name: - cached_file_path = '\\'.join([cache_directory_name, cached_file_path]) - event_values['cached_file_path'] = cached_file_path - http_headers = event_values.get('http_headers', None) if http_headers: event_values['http_headers'] = http_headers.replace('\r\n', ' - ') manager.FormattersManager.RegisterEventFormatterHelpers([ - MsiecfLeakFormatter, MsiecfUrlFormatter]) + MSIECFCachedPathFormatterHelper, MSIECFHTTPHeadersventFormatterHelper]) diff --git a/plaso/formatters/shell_items.py b/plaso/formatters/shell_items.py index 344e8cedce..8af6cccb91 100644 --- a/plaso/formatters/shell_items.py +++ b/plaso/formatters/shell_items.py @@ -7,10 +7,11 @@ from plaso.formatters import manager -class ShellItemFileEntryEventFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Windows shell item file entry event values.""" +class ShellItemFileEntryNameFormatterHelper( + interface.CustomEventFormatterHelper): + """Windows shell item file entry formatter helper.""" - DATA_TYPE = 'windows:shell_item:file_entry' + IDENTIFIER = 'shell_item_file_entry_name' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -24,4 +25,4 @@ def FormatEventValues(self, event_values): manager.FormattersManager.RegisterEventFormatterHelper( - ShellItemFileEntryEventFormatter) + ShellItemFileEntryNameFormatterHelper) diff --git a/plaso/formatters/winlnk.py b/plaso/formatters/winlnk.py index 34cbbfb1a3..74c410e7f6 100644 --- a/plaso/formatters/winlnk.py +++ b/plaso/formatters/winlnk.py @@ -7,10 +7,11 @@ from plaso.formatters import manager -class WinLnkLinkFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Windows Shortcut (LNK) link event values.""" +class WindowsShortcutLinkedPathFormatterHelper( + interface.CustomEventFormatterHelper): + """Windows Shortcut (LNK) linked path formatter helper.""" - DATA_TYPE = 'windows:lnk:link' + IDENTIFIER = 'windows_shortcut_linked_path' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -18,9 +19,6 @@ def FormatEventValues(self, event_values): Args: event_values (dict[str, object]): event values. """ - if 'description' not in event_values: - event_values['description'] = 'Empty description' - linked_path = event_values.get('local_path', None) if not linked_path: linked_path = event_values.get('network_path', None) @@ -35,4 +33,5 @@ def FormatEventValues(self, event_values): event_values['linked_path'] = linked_path or 'Unknown' -manager.FormattersManager.RegisterEventFormatterHelper(WinLnkLinkFormatter) +manager.FormattersManager.RegisterEventFormatterHelper( + WindowsShortcutLinkedPathFormatterHelper) diff --git a/plaso/formatters/winprefetch.py b/plaso/formatters/winprefetch.py index 75cfeb86a4..19661db981 100644 --- a/plaso/formatters/winprefetch.py +++ b/plaso/formatters/winprefetch.py @@ -7,10 +7,28 @@ from plaso.formatters import manager -class WinPrefetchExecutionFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Windows Prefetch execution event values.""" +class WindowsPrefetchPathHintsFormatterHelper( + interface.CustomEventFormatterHelper): + """Windows Prefetch path hints formatter helper.""" - DATA_TYPE = 'windows:prefetch:execution' + IDENTIFIER = 'windows_prefetch_path_hints' + + def FormatEventValues(self, event_values): + """Formats event values using the helper. + + Args: + event_values (dict[str, object]): event values. + """ + path_hints = event_values.get('path_hints', None) + if path_hints: + event_values['path_hints'] = '; '.join(path_hints) + + +class WindowsPrefetchVolumesStringFormatterHelper( + interface.CustomEventFormatterHelper): + """Windows Prefetch volumes string formatter helper.""" + + IDENTIFIER = 'windows_prefetch_volumes_string' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -21,12 +39,14 @@ def FormatEventValues(self, event_values): number_of_volumes = event_values.get('number_of_volumes', 0) volume_serial_numbers = event_values.get('volume_serial_numbers', None) volume_device_paths = event_values.get('volume_device_paths', None) + volumes_strings = [] for volume_index in range(0, number_of_volumes): if not volume_serial_numbers: volume_serial_number = 'UNKNOWN' else: - volume_serial_number = volume_serial_numbers[volume_index] + volume_serial_number = '0x{0:08X}'.format( + volume_serial_numbers[volume_index]) if not volume_device_paths: volume_device_path = 'UNKNOWN' @@ -34,17 +54,13 @@ def FormatEventValues(self, event_values): volume_device_path = volume_device_paths[volume_index] volumes_strings.append(( - 'volume: {0:d} [serial number: 0x{1:08X}, device path: ' - '{2:s}]').format( + 'volume: {0:d} [serial number: {1:s}, device path: {2:s}]').format( volume_index + 1, volume_serial_number, volume_device_path)) if volumes_strings: event_values['volumes_string'] = ', '.join(volumes_strings) - path_hints = event_values.get('path_hints', []) - if path_hints: - event_values['path_hints'] = '; '.join(path_hints) - -manager.FormattersManager.RegisterEventFormatterHelper( - WinPrefetchExecutionFormatter) +manager.FormattersManager.RegisterEventFormatterHelpers([ + WindowsPrefetchPathHintsFormatterHelper, + WindowsPrefetchVolumesStringFormatterHelper]) diff --git a/plaso/formatters/winreg.py b/plaso/formatters/winreg.py index a460c9a822..3b4960c8b2 100644 --- a/plaso/formatters/winreg.py +++ b/plaso/formatters/winreg.py @@ -7,10 +7,11 @@ from plaso.formatters import manager -class WinRegistryGenericFormatter(interface.CustomEventFormatterHelper): - """Custom formatter for Windows Registry key or value event values.""" +class WindowsRegistryValuesFormatterHelper( + interface.CustomEventFormatterHelper): + """Windows Registry values formatter helper.""" - DATA_TYPE = 'windows:registry:key_value' + IDENTIFIER = 'windows_registry_values' def FormatEventValues(self, event_values): """Formats event values using the helper. @@ -24,4 +25,4 @@ def FormatEventValues(self, event_values): manager.FormattersManager.RegisterEventFormatterHelper( - WinRegistryGenericFormatter) + WindowsRegistryValuesFormatterHelper) diff --git a/plaso/formatters/yaml_formatters_file.py b/plaso/formatters/yaml_formatters_file.py index d84ef57a5a..337521c431 100644 --- a/plaso/formatters/yaml_formatters_file.py +++ b/plaso/formatters/yaml_formatters_file.py @@ -35,6 +35,7 @@ class YAMLFormattersFile(object): _SUPPORTED_KEYS = frozenset([ 'data_type', 'boolean_helpers', + 'custom_helpers', 'enumeration_helpers', 'flags_helpers', 'message', @@ -73,6 +74,30 @@ def _ReadBooleanHelpers(self, formatter, boolean_helpers_definition_values): formatter.AddHelper(helper) + def _ReadCustomHelpers(self, formatter, custom_helpers_definition_values): + """Reads custom helper definitions from a list. + + Args: + formatter (EventFormatter): an event formatter. + custom_helpers_definition_values (list[dict[str, object]]): + custom helpers definition values. + + Raises: + ParseError: if the format of the custom helper definitions are incorrect. + """ + for custom_helper in custom_helpers_definition_values: + identifier = custom_helper.get('identifier', None) + if not identifier: + raise errors.ParseError( + 'Invalid custom helper missing identifier.') + + input_attribute = custom_helper.get('input_attribute', None) + output_attribute = custom_helper.get('output_attribute', None) + + formatter.AddCustomHelper( + identifier, input_attribute=input_attribute, + output_attribute=output_attribute) + def _ReadEnumerationHelpers( self, formatter, enumeration_helpers_definition_values): """Reads enumeration helper definitions from a list. @@ -212,6 +237,9 @@ def _ReadFormatterDefinition(self, formatter_definition_values): boolean_helpers = formatter_definition_values.get('boolean_helpers', []) self._ReadBooleanHelpers(formatter, boolean_helpers) + custom_helpers = formatter_definition_values.get('custom_helpers', []) + self._ReadCustomHelpers(formatter, custom_helpers) + enumeration_helpers = formatter_definition_values.get( 'enumeration_helpers', []) self._ReadEnumerationHelpers(formatter, enumeration_helpers) diff --git a/tests/formatters/chrome.py b/tests/formatters/chrome.py index 5f020d6093..a687fad986 100644 --- a/tests/formatters/chrome.py +++ b/tests/formatters/chrome.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the Google Chrome history event formatters.""" +"""Tests for the Google Chrome history custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,15 +11,36 @@ from tests.formatters import test_lib -class ChromePageVisitedFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the Chrome page visited event formatter.""" +class ChromeHistoryTypedCountFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Google Chrome history typed count formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = chrome.ChromePageVisitedFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = chrome.ChromeHistoryTypedCountFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = {'typed_count': 0} + formatter_helper.FormatEventValues(event_values) + self.assertEqual( + event_values['url_typed_string'], '(URL not typed directly)') + + event_values = {'typed_count': 1} + formatter_helper.FormatEventValues(event_values) + self.assertEqual( + event_values['url_typed_string'], '(URL typed 1 time)') + + event_values = {'typed_count': 3} + formatter_helper.FormatEventValues(event_values) + self.assertEqual( + event_values['url_typed_string'], '(URL typed 3 times)') + + event_values = {'typed_count': -1} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['url_typed_string'], -1) + + event_values = {'typed_count': None} + formatter_helper.FormatEventValues(event_values) + self.assertNotIn('url_typed_string', event_values) if __name__ == '__main__': diff --git a/tests/formatters/chrome_preferences.py b/tests/formatters/chrome_preferences.py index df8f47a5e1..4e0d1c0ec9 100644 --- a/tests/formatters/chrome_preferences.py +++ b/tests/formatters/chrome_preferences.py @@ -11,17 +11,61 @@ from tests.formatters import test_lib -class ChromeContentSettingsExceptionsFormatter( +class ChromePreferencesPrimaryURLFormatterHelperTest( test_lib.EventFormatterTestCase): - """Tests for the Chrome extension installation event formatter.""" + """Tests for the Google Chrome preferences primary URL formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = ( - chrome_preferences.ChromeContentSettingsExceptionsFormatter()) - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = ( + chrome_preferences.ChromePreferencesPrimaryURLFormatterHelper()) - # TODO: add test for FormatEventValues. + event_values = {'primary_url': 'https://example.com'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['primary_url'], 'https://example.com') + + event_values = {'primary_url': ''} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['primary_url'], 'local file') + + event_values = {'primary_url': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['primary_url']) + + +class ChromePreferencesSecondaryURLFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Google Chrome preferences secondary URL formatter helper.""" + + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = ( + chrome_preferences.ChromePreferencesSecondaryURLFormatterHelper()) + + event_values = { + 'primary_url': 'https://example.com', + 'secondary_url': 'https://anotherexample.com'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual( + event_values['secondary_url'], 'https://anotherexample.com') + + event_values = { + 'primary_url': 'https://example.com', + 'secondary_url': 'https://example.com'} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['secondary_url']) + + event_values = { + 'primary_url': 'https://example.com', + 'secondary_url': ''} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['secondary_url'], 'local file') + + event_values = { + 'primary_url': 'https://example.com', + 'secondary_url': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['secondary_url']) if __name__ == '__main__': diff --git a/tests/formatters/file_system.py b/tests/formatters/file_system.py index 37b614a631..79c760ae31 100644 --- a/tests/formatters/file_system.py +++ b/tests/formatters/file_system.py @@ -11,26 +11,53 @@ from tests.formatters import test_lib -class NTFSFileStatEventFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the NFTS file system stat event formatter.""" +class NTFSFileReferenceFormatterHelperTest(test_lib.EventFormatterTestCase): + """Tests for the NTFS file reference formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = file_system.NTFSFileStatEventFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = file_system.NTFSFileReferenceFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = {'file_reference': 0x2000000000011 } + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['file_reference'], '17-2') + event_values = {'file_reference': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['file_reference']) -class NTFSUSNChangeEventFormatter(test_lib.EventFormatterTestCase): - """Tests for the NTFS USN change event formatter.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = file_system.NTFSUSNChangeEventFormatter() - self.assertIsNotNone(event_formatter) +class NTFSParentFileReferenceFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the NTFS parent file reference formatter helper.""" - # TODO: add test for FormatEventValues. + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = file_system.NTFSParentFileReferenceFormatterHelper() + + event_values = {'parent_file_reference': 0x2000000000011 } + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['parent_file_reference'], '17-2') + + event_values = {'parent_file_reference': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['parent_file_reference']) + + +class NTFSPathHintsFormatterHelper(test_lib.EventFormatterTestCase): + """Tests for the NTFS path hints formatter helper.""" + + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = file_system.NTFSPathHintsFormatterHelper() + + event_values = {'path_hints': ['path1', 'path2']} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['path_hints'], 'path1;path2') + + event_values = {'path_hints': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['path_hints']) if __name__ == '__main__': diff --git a/tests/formatters/firefox.py b/tests/formatters/firefox.py index c2f9eef072..76b4b7508c 100644 --- a/tests/formatters/firefox.py +++ b/tests/formatters/firefox.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the Firefox history event formatter.""" +"""Tests for the Mozilla Firefox history custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,15 +11,39 @@ from tests.formatters import test_lib -class FirefoxPageVisitFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the Firefox page visited event formatter.""" +class FirefoxHistoryTypedCountFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Mozilla Firefox history typed count formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = firefox.FirefoxPageVisitFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = firefox.FirefoxHistoryTypedCountFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = {'typed': '1'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['url_typed_string'], '(URL directly typed)') + + event_values = {'typed': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual( + event_values['url_typed_string'], '(URL not typed directly)') + + +class FirefoxHistoryURLHiddenFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Mozilla Firefox history URL hidden formatter helper.""" + + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = firefox.FirefoxHistoryURLHiddenFormatterHelper() + + event_values = {'hidden': '1'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['url_hidden_string'], '(URL hidden)') + + event_values = {'hidden': None} + formatter_helper.FormatEventValues(event_values) + self.assertNotIn('url_hidden_string', event_values) if __name__ == '__main__': diff --git a/tests/formatters/msiecf.py b/tests/formatters/msiecf.py index 917190fe93..4ff02d1bcc 100644 --- a/tests/formatters/msiecf.py +++ b/tests/formatters/msiecf.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the MSIECF event formatters.""" +"""Tests for the MSIE cache file custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,26 +11,46 @@ from tests.formatters import test_lib -class MsiecfLeakFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the MSIECF leak item event formatter.""" +class MSIECFCachedPathFormatterHelperTest(test_lib.EventFormatterTestCase): + """Tests for the MSIE cache file cached path formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = msiecf.MsiecfLeakFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = msiecf.MSIECFCachedPathFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = { + 'cached_filename': 'file', + 'cache_directory_name': 'directory'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['cached_file_path'], 'directory\\file') + event_values = { + 'cached_filename': 'file', + 'cache_directory_name': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['cached_file_path'], 'file') -class MsiecfUrlFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the MSIECF URL item event formatter.""" + event_values = { + 'cached_filename': None, + 'cache_directory_name': 'directory'} + formatter_helper.FormatEventValues(event_values) + self.assertNotIn('cached_file_path', event_values) - def testInitialization(self): - """Tests the initialization.""" - event_formatter = msiecf.MsiecfUrlFormatter() - self.assertIsNotNone(event_formatter) - # TODO: add test for FormatEventValues. +class MSIECFHTTPHeadersventFormatterHelperTest(test_lib.EventFormatterTestCase): + """Tests for the MSIE cache file HTTP headers formatter helper.""" + + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = msiecf.MSIECFHTTPHeadersventFormatterHelper() + + event_values = {'http_headers': 'header1\r\nheader2'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['http_headers'], 'header1 - header2') + + event_values = {'http_headers': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['http_headers']) if __name__ == '__main__': diff --git a/tests/formatters/shell_items.py b/tests/formatters/shell_items.py index f176822417..e867b298c6 100644 --- a/tests/formatters/shell_items.py +++ b/tests/formatters/shell_items.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the shell item event formatter.""" +"""Tests for the Windows shell item custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,15 +11,31 @@ from tests.formatters import test_lib -class ShellItemFileEntryEventFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the shell item event formatter.""" +class ShellItemFileEntryNameFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Windows shell item file entry name formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = shell_items.ShellItemFileEntryEventFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = shell_items.ShellItemFileEntryNameFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = { + 'long_name': 'long', + 'name': 'short'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['file_entry_name'], 'long') + + event_values = { + 'long_name': None, + 'name': 'short'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['file_entry_name'], 'short') + + event_values = { + 'long_name': None, + 'name': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['file_entry_name']) if __name__ == '__main__': diff --git a/tests/formatters/winlnk.py b/tests/formatters/winlnk.py index b0fb1fdfd1..ce1867b542 100644 --- a/tests/formatters/winlnk.py +++ b/tests/formatters/winlnk.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the Windows Shortcut (LNK) event formatter.""" +"""Tests for the Windows Shortcut (LNK) custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,15 +11,53 @@ from tests.formatters import test_lib -class WinLnkLinkFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the Windows Shortcut (LNK) event formatter.""" +class WindowsShortcutLinkedPathFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Windows Shortcut (LNK) linked path formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = winlnk.WinLnkLinkFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = winlnk.WindowsShortcutLinkedPathFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = { + 'local_path': 'local', + 'network_path': 'network', + 'relative_path': 'relative', + 'working_directory': 'cwd'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['linked_path'], 'local') + + event_values = { + 'local_path': None, + 'network_path': 'network', + 'relative_path': 'relative', + 'working_directory': 'cwd'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['linked_path'], 'network') + + event_values = { + 'local_path': None, + 'network_path': None, + 'relative_path': 'relative', + 'working_directory': 'cwd'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['linked_path'], 'cwd\\relative') + + event_values = { + 'local_path': None, + 'network_path': None, + 'relative_path': 'relative', + 'working_directory': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['linked_path'], 'relative') + + event_values = { + 'local_path': None, + 'network_path': None, + 'relative_path': None, + 'working_directory': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['linked_path'], 'Unknown') if __name__ == '__main__': diff --git a/tests/formatters/winprefetch.py b/tests/formatters/winprefetch.py index 1e7e4a00bc..48ce4e2df7 100644 --- a/tests/formatters/winprefetch.py +++ b/tests/formatters/winprefetch.py @@ -11,15 +11,67 @@ from tests.formatters import test_lib -class WinPrefetchExecutionFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the Windows Prefetch execution event formatter.""" +class WindowsPrefetchPathHintsFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Windows Prefetch path hints formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = winprefetch.WinPrefetchExecutionFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = winprefetch.WindowsPrefetchPathHintsFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = {'path_hints': ['path1', 'path2']} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['path_hints'], 'path1; path2') + + event_values = {'path_hints': None} + formatter_helper.FormatEventValues(event_values) + self.assertIsNone(event_values['path_hints']) + + +class WindowsPrefetchVolumesStringFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Windows Prefetch volumes string formatter helper.""" + + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = winprefetch.WindowsPrefetchVolumesStringFormatterHelper() + + expected_volumes_string = ( + 'volume: 1 [serial number: 0x12345678, device path: device1]') + + event_values = { + 'number_of_volumes': 1, + 'volume_device_paths': ['device1'], + 'volume_serial_numbers': [0x12345678]} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['volumes_string'], expected_volumes_string) + + expected_volumes_string = ( + 'volume: 1 [serial number: UNKNOWN, device path: device1]') + + event_values = { + 'number_of_volumes': 1, + 'volume_device_paths': ['device1'], + 'volume_serial_numbers': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['volumes_string'], expected_volumes_string) + + expected_volumes_string = ( + 'volume: 1 [serial number: 0x12345678, device path: UNKNOWN]') + + event_values = { + 'number_of_volumes': 1, + 'volume_device_paths': None, + 'volume_serial_numbers': [0x12345678]} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['volumes_string'], expected_volumes_string) + + event_values = { + 'number_of_volumes': 0, + 'volume_device_paths': None, + 'volume_serial_numbers': None} + formatter_helper.FormatEventValues(event_values) + self.assertNotIn('volumes_string', event_values) if __name__ == '__main__': diff --git a/tests/formatters/winreg.py b/tests/formatters/winreg.py index e296fd7f85..7e545ee642 100644 --- a/tests/formatters/winreg.py +++ b/tests/formatters/winreg.py @@ -1,6 +1,6 @@ #!/usr/bin/env python3 # -*- coding: utf-8 -*- -"""Tests for the Windows Registry key or value event formatter.""" +"""Tests for the Windows Registry custom event formatter helpers.""" from __future__ import unicode_literals @@ -11,15 +11,21 @@ from tests.formatters import test_lib -class WinRegistryGenericFormatterTest(test_lib.EventFormatterTestCase): - """Tests for the Windows Registry key or value event formatter.""" +class WindowsRegistryValuesFormatterHelperTest( + test_lib.EventFormatterTestCase): + """Tests for the Windows Registry values formatter helper.""" - def testInitialization(self): - """Tests the initialization.""" - event_formatter = winreg.WinRegistryGenericFormatter() - self.assertIsNotNone(event_formatter) + def testFormatEventValues(self): + """Tests the FormatEventValues function.""" + formatter_helper = winreg.WindowsRegistryValuesFormatterHelper() - # TODO: add test for FormatEventValues. + event_values = {'values': 'value1, value2'} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['values'], 'value1, value2') + + event_values = {'values': None} + formatter_helper.FormatEventValues(event_values) + self.assertEqual(event_values['values'], '(empty)') if __name__ == '__main__': diff --git a/tests/parsers/olecf_plugins/automatic_destinations.py b/tests/parsers/olecf_plugins/automatic_destinations.py index 89b35656bc..83f6708ca2 100644 --- a/tests/parsers/olecf_plugins/automatic_destinations.py +++ b/tests/parsers/olecf_plugins/automatic_destinations.py @@ -71,7 +71,6 @@ def testProcessVersion1(self): self.assertEqual(event_data.data_type, 'windows:lnk:link') expected_message = ( - '[Empty description] ' 'File size: 3545 ' 'File attribute flags: 0x00002020 ' 'Drive type: 3 ' @@ -81,8 +80,8 @@ def testProcessVersion1(self): 'Link target: ') expected_short_message = ( - '[Empty description] ' - 'C:\\Users\\nfury\\AppData\\Roaming\\Microsoft\\Windows\\Librarie...') + 'C:\\Users\\nfury\\AppData\\Roaming\\Microsoft\\Windows\\Libraries\\' + 'Documents.library-ms') self._TestGetMessageStrings( event_data, expected_message, expected_short_message)