# -*- coding: utf-8 -*-
# Copyright (c) 2017 CloudZero - ALL RIGHTS RESERVED - PROPRIETARY AND CONFIDENTIAL
# Unauthorized copying of this file and/or project, via any medium is strictly prohibited.
# Direct all questions to legal@cloudzero.com
import base64
import secrets
from typing import NamedTuple

from OpenSSL import crypto

KEY_BYTES = 2048
CIPHER = 'aes256'
PASSPHRASE_LENGTH = 32


class KeyPair(NamedTuple):
    private_key: crypto.PKey
    passphrase_bytes: bytes

    @property
    def public_key(self) -> str:
        raw_public_key = crypto.dump_publickey(crypto.FILETYPE_PEM, self.private_key)
        return ''.join(x for x in raw_public_key.decode().split('\n') if x and not x.startswith('-----'))

    @property
    def passphrase(self) -> str:
        return base64.standard_b64encode(self.passphrase_bytes).decode()

    @property
    def private_key_bytes(self) -> bytes:
        return crypto.dump_privatekey(crypto.FILETYPE_ASN1, self.private_key)

    @property
    def encrypted_private_key(self) -> bytes:
        return crypto.dump_privatekey(crypto.FILETYPE_PEM, self.private_key, CIPHER, self.passphrase_bytes)


def generate() -> KeyPair:
    private_key = crypto.PKey()
    private_key.generate_key(crypto.TYPE_RSA, KEY_BYTES)
    passphrase_bytes = secrets.token_bytes(PASSPHRASE_LENGTH)
    return KeyPair(private_key=private_key, passphrase_bytes=passphrase_bytes)


def load(encrypted_private_key: bytes, passphrase: str) -> KeyPair:
    passphrase_bytes = base64.standard_b64decode(passphrase)
    private_key = crypto.load_privatekey(crypto.FILETYPE_PEM, encrypted_private_key, passphrase_bytes)
    return KeyPair(private_key=private_key, passphrase_bytes=passphrase_bytes)
