plaso-rubanetra/plaso/parsers/sqlite_plugins/firefox_cookies.py
2020-04-06 18:48:34 +02:00

164 lines
6.0 KiB
Python

#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright 2014 The Plaso Project Authors.
# Please see the AUTHORS file for details on individual authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
"""Parser for the Firefox Cookie database."""
from plaso.events import time_events
from plaso.lib import errors
from plaso.lib import eventdata
from plaso.lib import timelib
# Register the cookie plugins.
from plaso.parsers import cookie_plugins # pylint: disable=unused-import
from plaso.parsers import sqlite
from plaso.parsers.cookie_plugins import interface as cookie_interface
from plaso.parsers.sqlite_plugins import interface
class FirefoxCookieEvent(time_events.TimestampEvent):
"""Convenience class for a Firefox Cookie event."""
DATA_TYPE = 'firefox:cookie:entry'
def __init__(
self, timestamp, usage, identifier, hostname, cookie_name, value, path,
secure, httponly):
"""Initializes the event.
Args:
timestamp: The timestamp value in WebKit format..
usage: Timestamp description string.
identifier: The row identifier.
hostname: The hostname of host that set the cookie value.
cookie_name: The name field of the cookie.
value: The value of the cookie.
path: An URI of the page that set the cookie.
secure: Indication if this cookie should only be transmitted over a secure
channel.
httponly: An indication that the cookie cannot be accessed through client
side script.
"""
super(FirefoxCookieEvent, self).__init__(timestamp, usage)
if hostname.startswith('.'):
hostname = hostname[1:]
self.offset = identifier
self.host = hostname
self.cookie_name = cookie_name
self.data = value
self.path = path
self.secure = True if secure else False
self.httponly = True if httponly else False
if self.secure:
scheme = u'https'
else:
scheme = u'http'
self.url = u'{0:s}://{1:s}{2:s}'.format(scheme, hostname, path)
class FirefoxCookiePlugin(interface.SQLitePlugin):
"""Parse Firefox Cookies file."""
NAME = 'firefox_cookies'
DESCRIPTION = u'Parser for Firefox cookies SQLite database files.'
# Define the needed queries.
QUERIES = [
(('SELECT id, baseDomain, name, value, host, path, expiry, lastAccessed, '
'creationTime, isSecure, isHttpOnly FROM moz_cookies'),
'ParseCookieRow')]
# The required tables common to Archived History and History.
REQUIRED_TABLES = frozenset(['moz_cookies'])
# Point to few sources for URL information.
URLS = [
(u'https://hg.mozilla.org/mozilla-central/file/349a2f003529/netwerk/'
u'cookie/nsCookie.h')]
def __init__(self):
"""Initializes a plugin object."""
super(FirefoxCookiePlugin, self).__init__()
self._cookie_plugins = cookie_interface.GetPlugins()
def ParseCookieRow(
self, parser_context, row, file_entry=None, parser_chain=None,
query=None, **unused_kwargs):
"""Parses a cookie row.
Args:
parser_context: A parser context object (instance of ParserContext).
row: The row resulting from the query.
file_entry: Optional file entry object (instance of dfvfs.FileEntry).
The default is None.
parser_chain: Optional string containing the parsing chain up to this
point. The default is None.
query: Optional query string. The default is None.
"""
if row['creationTime']:
event_object = FirefoxCookieEvent(
row['creationTime'], eventdata.EventTimestamp.CREATION_TIME,
row['id'], row['host'], row['name'], row['value'], row['path'],
row['isSecure'], row['isHttpOnly'])
parser_context.ProduceEvent(
event_object, query=query, parser_chain=parser_chain,
file_entry=file_entry)
if row['lastAccessed']:
event_object = FirefoxCookieEvent(
row['lastAccessed'], eventdata.EventTimestamp.ACCESS_TIME, row['id'],
row['host'], row['name'], row['value'], row['path'], row['isSecure'],
row['isHttpOnly'])
parser_context.ProduceEvent(
event_object, query=query, parser_chain=parser_chain,
file_entry=file_entry)
if row['expiry']:
# 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.
timestamp = timelib.Timestamp.FromPosixTime(row['expiry'])
event_object = FirefoxCookieEvent(
timestamp, u'Cookie Expires', row['id'], row['host'], row['name'],
row['value'], row['path'], row['isSecure'], row['isHttpOnly'])
parser_context.ProduceEvent(
event_object, query=query, parser_chain=parser_chain,
file_entry=file_entry)
# Go through all cookie plugins to see if there are is any specific parsing
# needed.
hostname = row['host']
if hostname.startswith('.'):
hostname = hostname[1:]
url = u'http{0:s}://{1:s}{2:s}'.format(
u's' if row['isSecure'] else u'', hostname, row['path'])
for cookie_plugin in self._cookie_plugins:
try:
cookie_plugin.Process(
parser_context, cookie_name=row['name'], cookie_data=row['value'],
url=url, file_entry=file_entry, parser_chain=parser_chain)
except errors.WrongPlugin:
pass
sqlite.SQLiteParser.RegisterPlugin(FirefoxCookiePlugin)