from functools import partialmethod

from clarabot_nano.utility.aio_sqlite import AbstractAioSQLiteDatabase


class FirstUseIdentityDatabase(AbstractAioSQLiteDatabase):
    """
    To prevent a malicious server from replacing the keyring of a peer account all peer trust-root keys are
    fingerprinted and stored. Checking them the next time the same keyring is loaded will prevent
    man-in-the-middle attacks.
    """

    def _initialise(self):
        """
        This database holds digital fingerprint of peer-account trust-root keys. We configure the db to use WAL
        for maximum performance and crash-resistant integrity, but not durability.
        """
        self._con.execute("PRAGMA journal_mode = WAL;")
        self._con.execute("PRAGMA synchronous = NORMAL;")

    def _setup(self):
        self._con.execute(
            "CREATE TABLE IF NOT EXISTS TofuFingerprints0 ("
            " account_id INTEGER,"
            " key_version TEXT,"
            " fingerprint BLOB,"
            " PRIMARY KEY (account_id, key_version)"
            ")"
        )

    def _get_tofu(self, account_id):
        """
        Get all first-use-trusted fingerprint of the trust roots for an account.
        """
        rows = self._con.execute(
            "SELECT key_version, fingerprint FROM TofuFingerprints0 WHERE account_id = ?",
            (account_id,),
        ).fetchall()
        tofu = dict()
        if rows:
            for row in rows:
                tofu[row[0]] = row[1]
        return tofu

    def _insert_tofu(self, account_id, key_fingerprint_map):
        """
        Insert new fingerprints.
        """
        c = self._con.cursor()
        for key_version, fingerprint in key_fingerprint_map.items():
            c.execute(
                "INSERT INTO TofuFingerprints0(account_id, key_version, fingerprint) VALUES (?, ?, ?)",
                (account_id, key_version, fingerprint),
            )

    get_tofu = partialmethod(AbstractAioSQLiteDatabase._run_job, _get_tofu)
    insert_tofu = partialmethod(AbstractAioSQLiteDatabase._run_job, _insert_tofu)
