Source code for plaso.parsers.sqlite_plugins.firefox_downloads

"""SQLite parser plugin for Mozilla Firefox downloads database files."""

import json

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 FirefoxDownloadEventData(events.EventData): """Firefox download event data. Attributes: end_time (dfdatetime.DateTimeValues): date and time the download was finished. full_path (str): full path of the target of the download. mime_type (str): mime type of the download. name (str): name of the download. offset (str): identifier of the row, from which the event data was extracted. query (str): SQL query that was used to obtain the event data. received_bytes (int): number of bytes received. referrer (str): referrer URL of the download. start_time (dfdatetime.DateTimeValues): date and time the download was started. temporary_location (str): temporary location of the download. total_bytes (int): total number of bytes of the download. url (str): source URL of the download. """ DATA_TYPE = "firefox:downloads:download"
[docs] def __init__(self): """Initializes event data.""" super().__init__(data_type=self.DATA_TYPE) self.end_time = None self.full_path = None self.mime_type = None self.name = None self.offset = None self.query = None self.received_bytes = None self.referrer = None self.start_time = None self.temporary_location = None self.total_bytes = None self.url = None
[docs] class Firefox118DownloadEventData(events.EventData): """Firefox download event data. Attributes: deleted (int): deleted state. download_state (int): state of the download. end_time (dfdatetime.DateTimeValues): date and time the download was finished. expiration (int): expiration. flags (int): flags associated with this download full_path (str): full path of the target of the download. mime_type (str): mime type of the download. name (str): name of the download. offset (str): identifier of the row, from which the event data was extracted. query (str): SQL query that was used to obtain the event data. received_bytes (int): number of bytes received. referrer (str): referrer URL of the download. start_time (dfdatetime.DateTimeValues): date and time the download was started. temporary_location (str): temporary location of the download. total_bytes (int): total number of bytes of the download. type (int): type field. url (str): source URL of the download. """ DATA_TYPE = "firefox:downloads:download"
[docs] def __init__(self): """Initializes event data.""" super().__init__(data_type=self.DATA_TYPE) self.deleted = None self.download_state = None self.end_time = None self.expiration = None self.flags = None self.full_path = None self.name = None self.query = None self.received_bytes = None self.start_time = None self.total_bytes = None self.type = None self.url = None
[docs] class FirefoxDownloadsPlugin(interface.SQLitePlugin): """SQLite parser plugin for Mozilla Firefox downloads database files. The Mozilla Firefox downloads database file is typically stored in: downloads.sqlite """ NAME = "firefox_downloads" DATA_FORMAT = "Mozilla Firefox downloads SQLite database (downloads.sqlite) file" REQUIRED_STRUCTURE = { "moz_downloads": frozenset( [ "id", "name", "source", "target", "tempPath", "startTime", "endTime", "state", "referrer", "currBytes", "maxBytes", "mimeType", ] ) } QUERIES = [ ( ( "SELECT moz_downloads.id, moz_downloads.name, moz_downloads.source, " "moz_downloads.target, moz_downloads.tempPath, " "moz_downloads.startTime, moz_downloads.endTime, moz_downloads.state, " "moz_downloads.referrer, moz_downloads.currBytes, " "moz_downloads.maxBytes, moz_downloads.mimeType " "FROM moz_downloads" ), "ParseDownloadsRow", ) ] SCHEMAS = [ { "moz_downloads": "CREATE TABLE moz_downloads (id INTEGER PRIMARY KEY, " "name TEXT, source TEXT, target TEXT, tempPath TEXT, startTime INTEGER, " "endTime INTEGER, state INTEGER, referrer TEXT, entityID TEXT, currBytes " "INTEGER NOT NULL DEFAULT 0, maxBytes INTEGER NOT NULL DEFAULT -1, " "mimeType TEXT, preferredApplication TEXT, preferredAction INTEGER " "NOT NULL DEFAULT 0, autoResume INTEGER NOT NULL DEFAULT 0)" } ]
[docs] def ParseDownloadsRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a downloads 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. """ query_hash = hash(query) event_data = FirefoxDownloadEventData() event_data.end_time = self._GetPosixTimeInMicrosecondsRowValue( query_hash, row, "endTime" ) event_data.full_path = self._GetRowValue(query_hash, row, "target") event_data.mime_type = self._GetRowValue(query_hash, row, "mimeType") event_data.name = self._GetRowValue(query_hash, row, "name") event_data.offset = self._GetRowValue(query_hash, row, "id") event_data.query = query event_data.received_bytes = self._GetRowValue(query_hash, row, "currBytes") event_data.referrer = self._GetRowValue(query_hash, row, "referrer") event_data.start_time = self._GetPosixTimeInMicrosecondsRowValue( query_hash, row, "startTime" ) event_data.temporary_location = self._GetRowValue(query_hash, row, "tempPath") event_data.total_bytes = self._GetRowValue(query_hash, row, "maxBytes") event_data.url = self._GetRowValue(query_hash, row, "source") parser_mediator.ProduceEventData(event_data)
[docs] class Firefox118DownloadsPlugin(interface.SQLitePlugin): """SQLite parser plugin for version 118 Firefox downloads database files. The version 118 Firefox downloads database file is typically stored in: places.sql """ NAME = "firefox_118_downloads" DATA_FORMAT = ( "Mozilla Firefox 118 downloads SQLite database (downloads.sqlite) file" ) REQUIRED_STRUCTURE = { "moz_annos": frozenset( [ "id", "place_id", "anno_attribute_id", "content", "flags", "expiration", "type", "dateAdded", "lastModified", ] ), "moz_places": frozenset(["id", "title", "url", "last_visit_date"]), } QUERIES = [ ( ( "SELECT annos1.content, annos2.flags, annos2.expiration, annos2.type, " "annos2.dateAdded, annos2.lastModified, annos2.content as dest_fpath, " "places.url, places.title, places.last_visit_date " "FROM moz_annos annos1, moz_annos annos2, moz_places places " "WHERE annos1.anno_attribute_id == (annos2.anno_attribute_id + 1) " "AND annos1.place_id == annos2.place_id " "AND annos1.place_id == places.id" ), "ParseDownloadsRow", ) ] SCHEMAS = [ { "moz_annos": "CREATE TABLE moz_annos (id INTEGER PRIMARY KEY, " "place_id INTEGER NOT NULL, anno_attribute_id INTEGER, " "content LONGVARCHAR, flags INTEGER DEFAULT 0, " "expiration INTEGER DEFAULT 0, type INTEGER DEFAULT 0, " "dateAdded INTEGER DEFAULT 0, lastModified INTEGER DEFAULT 0)" }, { "moz_places": "CREATE TABLE moz_places (id INTEGER PRIMARY KEY, " "url LONGVARCHAR, title LONGVARCHAR, rev_host LONGVARCHAR, " "visit_count INTEGER DEFAULT 0, hidden INTEGER DEFAULT 0 NOT NULL, " "typed INTEGER DEFAULT 0 NOT NULL, " "frecency INTEGER DEFAULT -1 NOT NULL, last_visit_date INTEGER, " "guid TEXT, foreign_count INTEGER DEFAULT 0 NOT NULL, " "url_hash INTEGER DEFAULT 0 NOT NULL , description TEXT, " "preview_image_url TEXT, site_name TEXT, " "origin_id INTEGER REFERENCES moz_origins(id), " "recalc_frecency INTEGER NOT NULL DEFAULT 0, alt_frecency INTEGER, " "recalc_alt_frecency INTEGER NOT NULL DEFAULT 0)" }, ]
[docs] def ParseDownloadsRow(self, parser_mediator, query, row, **unused_kwargs): """Parses a downloads 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. """ query_hash = hash(query) content = self._GetRowValue(query_hash, row, "content") # Content consists of a JSON object similar to: # { # 'state': 1, # 'deleted': False, # 'endTime': 1689722333589, # 'fileSize': 66383750 # } content_data = json.loads(content) event_data = Firefox118DownloadEventData() event_data.deleted = content_data.get("deleted") event_data.download_state = content_data.get("state") end_time = content_data.get("endTime") if end_time is not None: event_data.end_time = dfdatetime_posix_time.PosixTimeInMilliseconds( timestamp=end_time ) event_data.expiration = self._GetRowValue(query_hash, row, "expiration") event_data.flags = self._GetRowValue(query_hash, row, "flags") event_data.full_path = self._GetRowValue(query_hash, row, "dest_fpath") event_data.name = self._GetRowValue(query_hash, row, "title") event_data.query = query event_data.received_bytes = content_data.get("fileSize", 0) event_data.start_time = self._GetPosixTimeInMicrosecondsRowValue( query_hash, row, "dateAdded" ) event_data.total_bytes = content_data.get("fileSize", 0) event_data.type = self._GetRowValue(query_hash, row, "type") event_data.url = self._GetRowValue(query_hash, row, "url") parser_mediator.ProduceEventData(event_data)
sqlite.SQLiteParser.RegisterPlugins([FirefoxDownloadsPlugin, Firefox118DownloadsPlugin])