<gh_stars>0
#
# Copyright 2022 Venafi, Inc.
#
# 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.
#
import datetime
import logging as log
import time
import uuid

from cryptography import x509
from cryptography.hazmat.backends import default_backend
from cryptography.hazmat.primitives import hashes
from cryptography.hazmat.primitives import serialization

from .common import (ZoneConfig, CommonConnection, Policy, CertField, KeyType)
from .pem import parse_pem

ROOT_CA = b"""-----BEGIN CERTIFICATE-----
<KEY>
-----END CERTIFICATE-----
"""

ROOT_CA_KEY = b"""-----<KEY>
"""


def fake_user(email=None):
    fake_user_email = email or "<EMAIL>"
    fake_user_uuid = str(uuid.uuid4())
    fake_company_uuid = str(uuid.uuid4())
    company_domains = ['auth-demo.com', 'example.com']
    fake_company = 'Example Inc.'
    f = {'user': {'username': fake_user_email, 'id': fake_user_uuid, 'companyId': fake_company_uuid,
                  'firstname': 'John', 'lastname': 'Doe', 'emailAddress': fake_user_email, 'userType': 'EXTERNAL',
                  'userAccountType': 'WEB_UI', 'userStatus': 'ACTIVE', 'roles': ['ADMIN'],
                  'firstLoginDate': '2018-11-27T14:24:37.136+0000', 'creationDate': '2018-11-27T14:24:05.455+0000'},
         'company': {'id': fake_company_uuid, 'name': fake_company, 'companyType': 'TPP_CUSTOMER', 'active': True,
                     'creationDate': '2017-04-16T16:49:51.000+0000', 'domains': company_domains},
         'apiKey': {'userId': fake_user_uuid, 'username': fake_user_email, 'companyId': fake_company_uuid,
                    'apiVersion': 'ALL', 'apiKeyStatus': 'ACTIVE', 'creationDate': '2018-11-27T14:24:05.455+0000',
                    'validityStartDate': '2018-11-27T14:24:05.455+0000',
                    'validityEndDate': '2119-05-26T14:24:05.455+0000'}}
    return f


class FakeConnection(CommonConnection):
    def __init__(self, *args, **kwargs):
        super().__init__()
        self.status = "200"
        self._base_url = "fake"

    def __str__(self):
        return "[Fake]"

    def auth(self):
        return fake_user()

    def register(self, email):
        return fake_user(email)

    def request_cert(self, request, zone):
        if not request.csr:
            request.build_csr()
        data = {"PolicyDN": zone,
                "PKCS10": request.csr,
                "ObjectName": request.friendly_name,
                "CertificateDN": request.friendly_name,
                "DisableAutomaticRenewal": "true"}
        request.id = data['CertificateDN']
        log.debug(f"Certificate successfully requested with request id {request.id}.")
        return request

    def read_zone_conf(self, tag):
        policy = Policy()
        policy.key_types = list([KeyType(KeyType.RSA, x) for x in KeyType.ALLOWED_SIZES])
        z = ZoneConfig(
            organization=CertField(""),
            organizational_unit=CertField(""),
            country=CertField(""),
            province=CertField(""),
            locality=CertField(""),
            policy=policy,
            key_type=policy.key_types[0],
        )
        return z

    def retrieve_cert(self, certificate_request):
        log.debug(f"Getting certificate status for id {certificate_request.id}")

        time.sleep(0.1)
        certificate_request._public_key_from_private()
        csr = x509.load_pem_x509_csr(certificate_request.csr.encode(), default_backend())

        root_ca_certificate = x509.load_pem_x509_certificate(ROOT_CA, default_backend())
        root_ca_private_key = serialization.load_pem_private_key(ROOT_CA_KEY, password=<PASSWORD>, backend=default_backend())

        # cn = x509.Name([x509.NameAttribute(NameOID.COMMON_NAME, certificate_request.common_name)])
        issuer = root_ca_certificate.issuer
        cert = x509.CertificateBuilder().subject_name(
            csr.subject
        ).issuer_name(
            issuer
        ).public_key(
            csr.public_key()
        ).serial_number(
            x509.random_serial_number()
        ).not_valid_before(
            datetime.datetime.utcnow()
        ).not_valid_after(
            # Our certificate will be valid for 10 days
            datetime.datetime.utcnow() + datetime.timedelta(days=10)
        ).add_extension(
            # csr_builder.extensions,
            x509.SubjectAlternativeName([x509.DNSName(u"localhost")]),
            critical=False,
            # Sign our certificate with our private key
        ).sign(root_ca_private_key, hashes.SHA256(), default_backend())

        log.info("This certificate is for test purposes only. Don't use it in production!")
        response = parse_pem(cert.public_bytes(serialization.Encoding.PEM).decode(), certificate_request.chain_option)
        response.key = certificate_request.private_key_pem
        return response

    def revoke_cert(self, request):
        raise NotImplementedError

    def renew_cert(self, request, reuse_key=False):
        log.debug("Renew is not supported in test mode.")
        raise NotImplementedError

    def read_zone_conf(self, tag):
        raise NotImplementedError

    def import_cert(self, request):
        raise NotImplementedError

    def get_policy(self, zone):
        raise NotImplementedError

    def set_policy(self, zone, policy_spec):
        raise NotImplementedError

    def request_ssh_cert(self, request):
        raise NotImplementedError

    def retrieve_ssh_cert(self, request):
        raise NotImplementedError

    def retrieve_ssh_config(self, ca_request):
        raise NotImplementedError
