"""SQLite parser plugin for Google Chrome autofill database files.

The Google Chrome autofill database (Web Data) file is typically stored in: Web Data
"""

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


class ChromeAutofillEventData(events.EventData):
    """Chrome Autofill event data.

    Attributes:
      creation_time (dfdatetime.DateTimeValues): creation date and time of
          the autofill entry.
      field_name (str): name of form field.
      last_used_time (dfdatetime.DateTimeValues): last date and time
          the autofill entry was last used.
      query (str): SQL query that was used to obtain the event data.
      usage_count (int): count of times value has been used in field_name.
      value (str): value populated in form field.
    """

    DATA_TYPE = "chrome:autofill:entry"

    def __init__(self):
        """Initializes event data."""
        super().__init__(data_type=self.DATA_TYPE)
        self.creation_time = None
        self.field_name = None
        self.last_used_time = None
        self.query = None
        self.usage_count = None
        self.value = None


class ChromeAutofillPlugin(interface.SQLitePlugin):
    """SQLite parser plugin for Google Chrome autofill database files."""

    NAME = "chrome_autofill"
    DATA_FORMAT = "Google Chrome autofill SQLite database (Web Data) file"

    REQUIRED_STRUCTURE = {
        "autofill": frozenset(
            ["count", "date_created", "date_last_used", "name", "value"]
        )
    }

    QUERIES = [
        (
            (
                "SELECT count, date_created, date_last_used, name, value "
                "FROM autofill"
            ),
            "_ParseAutofillRow",
        )
    ]

    SCHEMAS = [
        {
            "autofill": (
                "CREATE TABLE autofill (name VARCHAR, value VARCHAR, value_lower "
                "VARCHAR, date_created INTEGER DEFAULT 0, date_last_used INTEGER "
                "DEFAULT 0, count INTEGER DEFAULT 1, PRIMARY KEY (name, value))"
            ),
            "autofill_model_type_state": (
                "CREATE TABLE autofill_model_type_state (id INTEGER PRIMARY KEY, "
                "value BLOB)"
            ),
            "autofill_profile_emails": (
                "CREATE TABLE autofill_profile_emails ( guid VARCHAR, email VARCHAR)"
            ),
            "autofill_profile_names": (
                "CREATE TABLE autofill_profile_names ( guid VARCHAR, first_name "
                "VARCHAR, middle_name VARCHAR, last_name VARCHAR, full_name "
                "VARCHAR)"
            ),
            "autofill_profile_phones": (
                "CREATE TABLE autofill_profile_phones ( guid VARCHAR, number "
                "VARCHAR)"
            ),
            "autofill_profiles": (
                "CREATE TABLE autofill_profiles ( guid VARCHAR PRIMARY KEY, "
                "company_name VARCHAR, street_address VARCHAR, dependent_locality "
                "VARCHAR, city VARCHAR, state VARCHAR, zipcode VARCHAR, "
                "sorting_code VARCHAR, country_code VARCHAR, date_modified INTEGER "
                "NOT NULL DEFAULT 0, origin VARCHAR DEFAULT '', language_code "
                "VARCHAR, use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER "
                "NOT NULL DEFAULT 0, validity_bitfield UNSIGNED NOT NULL DEFAULT 0)"
            ),
            "autofill_profiles_trash": (
                "CREATE TABLE autofill_profiles_trash ( guid VARCHAR)"
            ),
            "autofill_sync_metadata": (
                "CREATE TABLE autofill_sync_metadata (storage_key VARCHAR PRIMARY "
                "KEY NOT NULL,value BLOB)"
            ),
            "credit_cards": (
                "CREATE TABLE credit_cards ( guid VARCHAR PRIMARY KEY, name_on_card "
                "VARCHAR, expiration_month INTEGER, expiration_year INTEGER, "
                "card_number_encrypted BLOB, date_modified INTEGER NOT NULL DEFAULT "
                "0, origin VARCHAR DEFAULT '', use_count INTEGER NOT NULL DEFAULT "
                "0, use_date INTEGER NOT NULL DEFAULT 0, billing_address_id "
                "VARCHAR)"
            ),
            "keywords": (
                "CREATE TABLE keywords (id INTEGER PRIMARY KEY,short_name VARCHAR "
                "NOT NULL,keyword VARCHAR NOT NULL,favicon_url VARCHAR NOT NULL,url "
                "VARCHAR NOT NULL,safe_for_autoreplace INTEGER,originating_url "
                "VARCHAR,date_created INTEGER DEFAULT 0,usage_count INTEGER DEFAULT "
                "0,input_encodings VARCHAR,suggest_url VARCHAR,prepopulate_id "
                "INTEGER DEFAULT 0,created_by_policy INTEGER DEFAULT "
                "0,last_modified INTEGER DEFAULT 0,sync_guid VARCHAR,alternate_urls "
                "VARCHAR,image_url VARCHAR,search_url_post_params "
                "VARCHAR,suggest_url_post_params VARCHAR,image_url_post_params "
                "VARCHAR,new_tab_url VARCHAR,last_visited INTEGER DEFAULT 0)"
            ),
            "masked_credit_cards": (
                "CREATE TABLE masked_credit_cards (id VARCHAR,status "
                "VARCHAR,name_on_card VARCHAR,network VARCHAR,last_four "
                "VARCHAR,exp_month INTEGER DEFAULT 0,exp_year INTEGER DEFAULT 0, "
                "bank_name VARCHAR, type INTEGER DEFAULT 0)"
            ),
            "meta": (
                "CREATE TABLE meta(key LONGVARCHAR NOT NULL UNIQUE PRIMARY KEY, "
                "value LONGVARCHAR)"
            ),
            "payment_method_manifest": (
                "CREATE TABLE payment_method_manifest ( expire_date INTEGER NOT "
                "NULL DEFAULT 0, method_name VARCHAR, web_app_id VARCHAR)"
            ),
            "server_address_metadata": (
                "CREATE TABLE server_address_metadata (id VARCHAR NOT "
                "NULL,use_count INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT "
                "NULL DEFAULT 0, has_converted BOOL NOT NULL DEFAULT FALSE)"
            ),
            "server_addresses": (
                "CREATE TABLE server_addresses (id VARCHAR,company_name "
                "VARCHAR,street_address VARCHAR,address_1 VARCHAR,address_2 "
                "VARCHAR,address_3 VARCHAR,address_4 VARCHAR,postal_code "
                "VARCHAR,sorting_code VARCHAR,country_code VARCHAR,language_code "
                "VARCHAR, recipient_name VARCHAR, phone_number VARCHAR)"
            ),
            "server_card_metadata": (
                "CREATE TABLE server_card_metadata (id VARCHAR NOT NULL,use_count "
                "INTEGER NOT NULL DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, "
                "billing_address_id VARCHAR)"
            ),
            "unmasked_credit_cards": (
                "CREATE TABLE unmasked_credit_cards (id "
                "VARCHAR,card_number_encrypted VARCHAR, use_count INTEGER NOT NULL "
                "DEFAULT 0, use_date INTEGER NOT NULL DEFAULT 0, unmask_date "
                "INTEGER NOT NULL DEFAULT 0)"
            ),
            "web_app_manifest_section": (
                "CREATE TABLE web_app_manifest_section ( expire_date INTEGER NOT "
                "NULL DEFAULT 0, id VARCHAR, min_version INTEGER NOT NULL DEFAULT "
                "0, fingerprints BLOB)"
            ),
        }
    ]

    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)

    def _ParseAutofillRow(self, parser_mediator, query, row, **unused_kwargs):
        """Parses an autofill 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.
        """
        query_hash = hash(query)

        event_data = ChromeAutofillEventData()
        event_data.creation_time = self._GetDateTimeRowValue(
            query_hash, row, "date_created"
        )
        event_data.field_name = self._GetRowValue(query_hash, row, "name")
        event_data.last_used_time = self._GetDateTimeRowValue(
            query_hash, row, "date_last_used"
        )
        event_data.query = query
        event_data.usage_count = self._GetRowValue(query_hash, row, "count")
        event_data.value = self._GetRowValue(query_hash, row, "value")

        parser_mediator.ProduceEventData(event_data)


sqlite.SQLiteParser.RegisterPlugin(ChromeAutofillPlugin)
