from __future__ import annotations

import base64
import json
import re


def common_auth_test(auth):
    private_key_pem = auth.initialize_private_key()
    public_key_pem = auth.public_key_pem

    extract_pem_key(private_key_pem, private=True)
    extract_pem_key(public_key_pem, private=False)

    request = dict(hello='World')
    auth.sign_request(request)

    verify_signature(request, public_key_pem)


def extract_pem_key(value, private):
    assert isinstance(value, type(u''))

    key_type = '(EC )?PRIVATE' if private else 'PUBLIC'
    pattern = r'^-----BEGIN ' + key_type + r' KEY-----\n(?P<key>.*?)\n-----END ' + key_type + r' KEY-----\n$'
    match = re.search(pattern, value, flags=re.DOTALL)

    assert match, 'key "%s" does not match pattern "%s"' % (value, pattern)

    base64.b64decode(match.group('key'))  # make sure the key can be decoded


def verify_signature(request, public_key_pem):
    signature = request.pop('signature')
    payload_bytes = json.dumps(request, sort_keys=True).encode()

    assert isinstance(signature, type(u''))

    from cryptography.hazmat.backends import default_backend
    from cryptography.hazmat.primitives import hashes
    from cryptography.hazmat.primitives.asymmetric import ec
    from cryptography.hazmat.primitives.serialization import load_pem_public_key

    public_key = load_pem_public_key(public_key_pem.encode(), default_backend())

    public_key.verify(
        base64.b64decode(signature.encode()),
        payload_bytes,
        ec.ECDSA(hashes.SHA256()),
    )
