"""SQLite parser plugin for Mozilla Firefox cookies database files."""
from dfdatetime import posix_time as dfdatetime_posix_time
from plaso.containers import events
from plaso.lib import cookie_plugins_helper
from plaso.parsers import sqlite
from plaso.parsers.sqlite_plugins import interface
[docs]
class FirefoxCookieEventData(events.EventData):
"""Firefox Cookie event data.
Attributes:
access_time (dfdatetime.DateTimeValues): date and time the cookie
was last accessed.
cookie_name (str): name field of the cookie.
creation_time (dfdatetime.DateTimeValues): date and time the cookie
was created.
data (str): cookie data.
expiration_time (dfdatetime.DateTimeValues): date and time the cookie
expires.
httponly (bool): True if the cookie cannot be accessed through client
side script.
host (str): hostname of host that set the cookie value.
offset (str): identifier of the row, from which the event data was
extracted.
path (str): URI of the page that set the cookie.
query (str): SQL query that was used to obtain the event data.
secure (bool): True if the cookie should only be transmitted over a secure
channel.
"""
DATA_TYPE = "firefox:cookie:entry"
[docs]
def __init__(self):
"""Initializes event data."""
super().__init__(data_type=self.DATA_TYPE)
self.access_time = None
self.cookie_name = None
self.creation_time = None
self.data = None
self.expiration_time = None
self.host = None
self.httponly = None
self.offset = None
self.path = None
self.query = None
self.secure = None
self.url = None
[docs]
class BaseFirefoxCookiePlugin(
interface.SQLitePlugin, cookie_plugins_helper.CookiePluginsHelper
):
"""Shared SQLite parser plugin for Mozilla Firefox cookies database files."""
def _GetPosixTimeDateTimeRowValue(self, query_hash, row, value_name):
"""Retrieves a POSIX time (in seconds) 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)
# Note that pysqlite3 can return an empty string for a NULL value.
# Also see: https://github.com/log2timeline/plaso/issues/4961
if timestamp is None or not isinstance(timestamp, int):
return None
return dfdatetime_posix_time.PosixTime(timestamp=timestamp)
[docs]
def ParseCookieRow(self, parser_mediator, query, row, **unused_kwargs):
"""Parses a cookie 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)
cookie_data = self._GetRowValue(query_hash, row, "value")
cookie_name = self._GetRowValue(query_hash, row, "name")
hostname = self._GetRowValue(query_hash, row, "host")
if hostname.startswith("."):
hostname = hostname[1:]
is_secure = bool(self._GetRowValue(query_hash, row, "isSecure"))
if is_secure:
url_scheme = "https"
else:
url_scheme = "http"
path = self._GetRowValue(query_hash, row, "path")
url = f"{url_scheme:s}://{hostname:s}{path:s}"
event_data = FirefoxCookieEventData()
event_data.access_time = self._GetPosixTimeInMicrosecondsRowValue(
query_hash, row, "lastAccessed"
)
event_data.cookie_name = cookie_name
event_data.creation_time = self._GetPosixTimeInMicrosecondsRowValue(
query_hash, row, "creationTime"
)
event_data.data = cookie_data
event_data.host = hostname
event_data.httponly = bool(self._GetRowValue(query_hash, row, "isHttpOnly"))
event_data.offset = self._GetRowValue(query_hash, row, "id")
event_data.path = path
event_data.query = query
event_data.secure = is_secure
event_data.url = url
# Expiry time (nsCookieService::GetExpiry in
# netwerk/cookie/nsCookieService.cpp).
# It's calculated as the difference between the server time and the time
# the server wants the cookie to expire and adding that difference to the
# client time. This localizes the client time regardless of whether or not
# the TZ environment variable was set on the client.
event_data.expiration_time = self._GetPosixTimeDateTimeRowValue(
query_hash, row, "expiry"
)
parser_mediator.ProduceEventData(event_data)
self._ParseCookie(parser_mediator, cookie_name, cookie_data, url)
[docs]
class FirefoxCookie2Plugin(BaseFirefoxCookiePlugin):
"""SQLite parser plugin for Mozilla Firefox cookies schema 2 databases.
Also see:
https://hg-edge.mozilla.org/mozilla-central/file/349a2f003529/netwerk/cookie/nsCookie.h
"""
NAME = "firefox_2_cookies"
DATA_FORMAT = "Mozilla Firefox cookies SQLite database file version 2"
REQUIRED_STRUCTURE = {
"moz_cookies": frozenset(
[
"baseDomain",
"creationTime",
"expiry",
"host",
"id",
"isHttpOnly",
"isSecure",
"lastAccessed",
"name",
"path",
"value",
]
)
}
QUERIES = [
(
(
"SELECT id, baseDomain, name, value, host, path, expiry, "
"lastAccessed, creationTime, isSecure, isHttpOnly FROM moz_cookies"
),
"ParseCookieRow",
)
]
SCHEMAS = [
{
"moz_cookies": (
"CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, baseDomain TEXT, "
"appId INTEGER DEFAULT 0, inBrowserElement INTEGER DEFAULT 0, name "
"TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, "
"lastAccessed INTEGER, creationTime INTEGER, isSecure INTEGER, "
"isHttpOnly INTEGER, CONSTRAINT moz_uniqueid UNIQUE (name, host, "
"path, appId, inBrowserElement))"
)
}
]
[docs]
class FirefoxCookie10Plugin(BaseFirefoxCookiePlugin):
"""SQLite parser plugin for Mozilla Firefox cookies schema 10 databases.
In schema 10 baseDomain was removed.
"""
NAME = "firefox_10_cookies"
DATA_FORMAT = "Mozilla Firefox cookies SQLite database file version 10"
REQUIRED_STRUCTURE = {
"moz_cookies": frozenset(
[
"id",
"name",
"value",
"host",
"path",
"expiry",
"lastAccessed",
"creationTime",
"isSecure",
"isHttpOnly",
]
)
}
QUERIES = [
(
(
"SELECT id, name, value, host, path, expiry, "
"lastAccessed, creationTime, isSecure, isHttpOnly FROM moz_cookies"
),
"ParseCookieRow",
)
]
SCHEMAS = [
{
"moz_cookies": (
"CREATE TABLE moz_cookies (id INTEGER PRIMARY KEY, "
"appId INTEGER DEFAULT 0, inBrowserElement INTEGER DEFAULT 0, name "
"TEXT, value TEXT, host TEXT, path TEXT, expiry INTEGER, "
"lastAccessed INTEGER, creationTime INTEGER, isSecure INTEGER, "
"isHttpOnly INTEGER, CONSTRAINT moz_uniqueid UNIQUE (name, host, "
"path, appId, inBrowserElement))"
)
}
]
sqlite.SQLiteParser.RegisterPlugins([FirefoxCookie2Plugin, FirefoxCookie10Plugin])