diff --git a/l2tscaffolder/scaffolders/plaso_sqlite.py b/l2tscaffolder/scaffolders/plaso_sqlite.py index 35d5e47..67a37ff 100644 --- a/l2tscaffolder/scaffolders/plaso_sqlite.py +++ b/l2tscaffolder/scaffolders/plaso_sqlite.py @@ -25,6 +25,9 @@ def ValidateAnswer(self, answer: dict): by attempting to run it against an empty SQLite database stored in memory. + The function also makes sure the key value confirms to the + style guide of plaso, to be in the form of CamelCase, eg. BookmarkRow. + Args: answer (dict): the answer to the question asked. @@ -35,6 +38,21 @@ def ValidateAnswer(self, answer: dict): temp_db = sqlite3.connect(':memory:') for query_name, query in answer.items(): + if ' ' in query_name: + raise errors.UnableToConfigure(( + 'Wrong format for key value, key cannot contain spaces ' + '[{0:s}]').format(query_name)) + + if not query_name[0].isupper(): + raise errors.UnableToConfigure(( + 'Wrong format for key value, key needs to start with an ' + 'upper case letter [{0:s}]').format(query_name)) + + if query_name.startswith('Parse'): + raise errors.UnableToConfigure(( + 'Wrong format for key value, key should not start with the ' + 'Parse (that is added by template) [{0:s}]').format(query_name)) + try: temp_db.execute(query) except ValueError as exception: @@ -93,9 +111,15 @@ class PlasoSQLiteScaffolder(plaso.PlasoPluginScaffolder): QUESTIONS = [ SQLQuestion( attribute='queries', prompt=( - 'Define the name of the SQL query (key) as well as the actual SQL ' - 'queries (value) this plugin will execute'), - key_prompt='Query Name', value_prompt='SQL Statement'), + 'Define the name of the callback function (key) that will be\n' + 'called for every row returned from the SQL query (value).\n' + 'The plugin will execute the SQL query and call the callback\n' + 'once for each resulting row. The name of the function should\n' + 'follow style guide and be descriptive. An example of that is\n' + 'a SQL statement that fetches bookmarks, the key name should be\n' + 'Bookmark, or if the SQL statement collects GPS coordinates\n' + 'it could be called Location.'), + key_prompt='Callback function name', value_prompt='SQL Statement'), interface.ListQuestion( attribute='required_tables', prompt='List of required tables')] diff --git a/l2tscaffolder/templates/sqlite_plugin.jinja2 b/l2tscaffolder/templates/sqlite_plugin.jinja2 index 8ad4bbf..669cd80 100644 --- a/l2tscaffolder/templates/sqlite_plugin.jinja2 +++ b/l2tscaffolder/templates/sqlite_plugin.jinja2 @@ -14,7 +14,7 @@ from plaso.lib import eventdata from plaso.parsers import sqlite from plaso.parsers.sqlite_plugins import interface {% for query_name, query in queries.items()|sort(false) %} -class {{ class_name }}{{ query_name|capitalize}}EventData(events.EventData): +class {{ class_name }}{{ query_name }}EventData(events.EventData): """{{ plugin_name|replace('_',' ')}} {{query_name|lower}} event data. Attributes: @@ -40,7 +40,7 @@ class {{ class_name }}Plugin(interface.SQLitePlugin): {% for query_name, query in queries.items()|sort(false) %} (( '{{ query|wordwrap(width=69,break_long_words=False,wrapstring="'\n '") }}'), - 'Parse{{ query_name|capitalize }}Row'){% if not loop.last %},{% endif %}{% endfor %}] + 'Parse{{ query_name }}Row'){% if not loop.last %},{% endif %}{% endfor %}] REQUIRED_TABLES = frozenset([ {% for table in required_tables %}'{{ table }}'{% if not loop.last %}, @@ -51,7 +51,7 @@ class {{ class_name }}Plugin(interface.SQLitePlugin): '{{schema|wordwrap(width=64,wrapstring="'\n '")}}'){% if not loop.last %},{% endif %}{% endfor%}}] {% for query_name, query in queries.items()|sort(false) %} - def Parse{{ query_name|capitalize }}Row(self, parser_mediator, query, row, **unused_kwargs): + def Parse{{ query_name }}Row(self, parser_mediator, query, row, **unused_kwargs): """Parses a row from the database. Args: diff --git a/tests/scaffolders/plaso_sqlite.py b/tests/scaffolders/plaso_sqlite.py index b9bb10e..b45298d 100644 --- a/tests/scaffolders/plaso_sqlite.py +++ b/tests/scaffolders/plaso_sqlite.py @@ -54,8 +54,8 @@ def testPlasoSQLiteScaffolder(self): scaffolder.RaiseIfNotReady() queries = { - 'strange': 'SELECT name, address, ssn FROM strange', - 'foobar': ( + 'Strange': 'SELECT name, address, ssn FROM strange', + 'Foobar': ( 'SELECT f1.foo, f2.bar AS Bar FROM foobar_one AS f1, ' 'foobar_two as f2 WHERE f1.id = f2.id')} required_tables = ['foobar_one', 'foobar_two', 'strange_table']