Source code for plaso.parsers.sqlite_plugins.gdrive

# -*- coding: utf-8 -*-
"""SQLite parser plugin for Google Drive snapshot database files."""

from dfdatetime import posix_time as dfdatetime_posix_time

from plaso.containers import events
from plaso.parsers import sqlite
from plaso.parsers.sqlite_plugins import interface


[docs] class GoogleDriveSnapshotCloudEntryEventData(events.EventData): """Google Drive snapshot cloud entry event data. Attributes: creation_time (dfdatetime.DateTimeValues): date and time the snapshot cloud entry was created. doc_type (int): document type. modification_time (dfdatetime.DateTimeValues): date and time the snapshot cloud entry was last modified. path (str): path of the file. query (str): SQL query that was used to obtain the event data. shared (bool): True if the file is shared, False if the file is private. size (int): size of the file. url (str): URL of the file. """ DATA_TYPE = 'gdrive:snapshot:cloud_entry'
[docs] def __init__(self): """Initializes event data.""" super(GoogleDriveSnapshotCloudEntryEventData, self).__init__( data_type=self.DATA_TYPE) self.creation_time = None self.document_type = None self.modification_time = None self.path = None self.query = None self.shared = None self.size = None self.url = None
[docs] class GoogleDriveSnapshotLocalEntryEventData(events.EventData): """Google Drive snapshot local entry event data. Attributes: modification_time (dfdatetime.DateTimeValues): date and time the snapshot local entry was last modified. path (str): path of the file. query (str): SQL query that was used to obtain the event data. size (int): size of the file. """ DATA_TYPE = 'gdrive:snapshot:local_entry'
[docs] def __init__(self): """Initializes event data.""" super(GoogleDriveSnapshotLocalEntryEventData, self).__init__( data_type=self.DATA_TYPE) self.modification_time = None self.path = None self.query = None self.size = None
[docs] class GoogleDrivePlugin(interface.SQLitePlugin): """SQLite parser plugin for Google Drive snapshot database files. The Google Drive snapshot database file is typically stored in: snapshot.db """ NAME = 'google_drive' DATA_FORMAT = 'Google Drive snapshot SQLite database (snapshot.db) file' REQUIRED_STRUCTURE = { 'cloud_entry': frozenset([ 'resource_id', 'filename', 'modified', 'created', 'size', 'doc_type', 'shared', 'checksum', 'url']), 'cloud_relations': frozenset([ 'parent_resource_id', 'child_resource_id']), 'local_entry': frozenset([ 'inode_number', 'filename', 'modified', 'checksum', 'size']), 'local_relations': frozenset([ 'child_inode_number', 'parent_inode_number'])} QUERIES = [ (('SELECT cloud_entry.resource_id, cloud_entry.filename, ' 'cloud_entry.modified, cloud_entry.created, cloud_entry.size, ' 'cloud_entry.doc_type, cloud_entry.shared, cloud_entry.checksum, ' 'cloud_entry.url, cloud_relations.parent_resource_id ' 'FROM cloud_entry, cloud_relations ' 'WHERE cloud_relations.child_resource_id = cloud_entry.resource_id ' 'AND cloud_entry.modified IS NOT NULL;'), 'ParseCloudEntryRow'), (('SELECT inode_number, filename, modified, checksum, size ' 'FROM local_entry WHERE modified IS NOT NULL;'), 'ParseLocalEntryRow')] SCHEMAS = [{ 'cloud_entry': ( 'CREATE TABLE cloud_entry (resource_id TEXT, filename TEXT, ' 'modified INTEGER, created INTEGER, acl_role INTEGER, doc_type ' 'INTEGER, removed INTEGER, url TEXT, size INTEGER, checksum TEXT, ' 'shared INTEGER, PRIMARY KEY (resource_id))'), 'cloud_relations': ( 'CREATE TABLE cloud_relations (child_resource_id TEXT, ' 'parent_resource_id TEXT, UNIQUE (child_resource_id, ' 'parent_resource_id), FOREIGN KEY (child_resource_id) REFERENCES ' 'cloud_entry(resource_id), FOREIGN KEY (parent_resource_id) ' 'REFERENCES cloud_entry(resource_id))'), 'local_entry': ( 'CREATE TABLE local_entry (inode_number INTEGER, filename TEXT, ' 'modified INTEGER, checksum TEXT, size INTEGER, PRIMARY KEY ' '(inode_number))'), 'local_relations': ( 'CREATE TABLE local_relations (child_inode_number INTEGER, ' 'parent_inode_number INTEGER, UNIQUE (child_inode_number), FOREIGN ' 'KEY (parent_inode_number) REFERENCES local_entry(inode_number), ' 'FOREIGN KEY (child_inode_number) REFERENCES ' 'local_entry(inode_number))'), 'mapping': ( 'CREATE TABLE mapping (inode_number INTEGER, resource_id TEXT, ' 'UNIQUE (inode_number), FOREIGN KEY (inode_number) REFERENCES ' 'local_entry(inode_number), FOREIGN KEY (resource_id) REFERENCES ' 'cloud_entry(resource_id))'), 'overlay_status': ( 'CREATE TABLE overlay_status (path TEXT, overlay_status INTEGER, ' 'PRIMARY KEY (path))')}] # Queries used to build cache. LOCAL_PATH_CACHE_QUERY = ( 'SELECT local_relations.child_inode_number, ' 'local_relations.parent_inode_number, local_entry.filename ' 'FROM local_relations, local_entry ' 'WHERE local_relations.child_inode_number = local_entry.inode_number') CLOUD_PATH_CACHE_QUERY = ( 'SELECT cloud_entry.filename, cloud_entry.resource_id, ' 'cloud_relations.parent_resource_id AS parent ' 'FROM cloud_entry, cloud_relations ' 'WHERE cloud_entry.doc_type = 0 ' 'AND cloud_entry.resource_id = cloud_relations.child_resource_id') def _GetDateTimeRowValue(self, query_hash, row, value_name): """Retrieves a date and time value from the row. Args: query_hash (int): hash of the query, that uniquely identifies the query that produced the row. row (sqlite3.Row): row. value_name (str): name of the value. Returns: dfdatetime.PosixTime: date and time value or None if not available. """ timestamp = self._GetRowValue(query_hash, row, value_name) if timestamp is None: return None return dfdatetime_posix_time.PosixTime(timestamp=timestamp)
[docs] def GetLocalPath(self, inode, cache, database): """Return local path for a given inode. Args: inode (int): inode number for the file. cache (SQLiteCache): cache. database (SQLiteDatabase): database. Returns: str: full path, including the filename of the given inode value. """ local_path = cache.GetResults('local_path') if not local_path: results = database.Query(self.LOCAL_PATH_CACHE_QUERY) cache.CacheQueryResults( results, 'local_path', 'child_inode_number', ('parent_inode_number', 'filename')) local_path = cache.GetResults('local_path') parent, path = local_path.get(inode, [None, None]) # TODO: Read the local_sync_root from the sync_config.db and use that # for a root value. root_value = '%local_sync_root%/' if not path: return root_value paths = [] while path: paths.append(path) parent, path = local_path.get(parent, [None, None]) if not paths: return root_value # Paths are built top level to root so we need to reverse the list to # represent them in the traditional order. paths.reverse() return root_value + '/'.join(paths)
[docs] def GetCloudPath(self, resource_id, cache, database): """Return cloud path given a resource id. Args: resource_id (str): resource identifier for the file. cache (SQLiteCache): cache. database (SQLiteDatabase): database. Returns: str: full path to the resource value. """ cloud_path = cache.GetResults('cloud_path') if not cloud_path: results = database.Query(self.CLOUD_PATH_CACHE_QUERY) cache.CacheQueryResults( results, 'cloud_path', 'resource_id', ('filename', 'parent')) cloud_path = cache.GetResults('cloud_path') if resource_id == 'folder:root': return '/' paths = [] parent_path, parent_id = cloud_path.get(resource_id, ['', '']) while parent_path: if parent_path == 'folder:root': break paths.append(parent_path) parent_path, parent_id = cloud_path.get(parent_id, ['', '']) if not paths: return '/' # Paths are built top level to root so we need to reverse the list to # represent them in the traditional order. paths.reverse() return '/{0:s}/'.format('/'.join(paths))
[docs] def ParseCloudEntryRow( self, parser_mediator, query, row, cache=None, database=None, **unused_kwargs): """Parses a cloud entry row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. query (str): query that created the row. row (sqlite3.Row): row. cache (SQLiteCache): cache. database (SQLiteDatabase): database. """ query_hash = hash(query) parent_resource_id = self._GetRowValue( query_hash, row, 'parent_resource_id') cloud_path = self.GetCloudPath(parent_resource_id, cache, database) filename = self._GetRowValue(query_hash, row, 'filename') event_data = GoogleDriveSnapshotCloudEntryEventData() event_data.creation_time = self._GetDateTimeRowValue( query_hash, row, 'created') event_data.document_type = self._GetRowValue(query_hash, row, 'doc_type') event_data.modification_time = self._GetDateTimeRowValue( query_hash, row, 'modified') event_data.path = ''.join([cloud_path, filename]) event_data.query = query event_data.shared = bool(self._GetRowValue(query_hash, row, 'shared')) event_data.size = self._GetRowValue(query_hash, row, 'size') event_data.url = self._GetRowValue(query_hash, row, 'url') parser_mediator.ProduceEventData(event_data)
[docs] def ParseLocalEntryRow( self, parser_mediator, query, row, cache=None, database=None, **unused_kwargs): """Parses a local entry row. Args: parser_mediator (ParserMediator): mediates interactions between parsers and other components, such as storage and dfVFS. query (str): query that created the row. row (sqlite3.Row): row. cache (Optional[SQLiteCache]): cache. database (Optional[SQLiteDatabase]): database. """ query_hash = hash(query) inode_number = self._GetRowValue(query_hash, row, 'inode_number') local_path = self.GetLocalPath(inode_number, cache, database) event_data = GoogleDriveSnapshotLocalEntryEventData() event_data.modification_time = self._GetDateTimeRowValue( query_hash, row, 'modified') event_data.path = local_path event_data.query = query event_data.size = self._GetRowValue(query_hash, row, 'size') parser_mediator.ProduceEventData(event_data)
sqlite.SQLiteParser.RegisterPlugin(GoogleDrivePlugin)