# Copyright (C) 2004-2014 Bastian Kleineidam
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
"""
Test https.
"""
import datetime
from unittest.mock import patch

from cryptography import x509
from cryptography.x509.oid import NameOID
from cryptography.hazmat.primitives import hashes, serialization
from cryptography.hazmat.primitives.asymmetric import rsa
from OpenSSL import crypto

from .httpserver import HttpsServerTest, CookieRedirectHttpRequestHandler
from .. import get_file

from linkcheck import httputil


class TestHttps(HttpsServerTest):
    """
    Test https: link checking.
    """

    def __init__(self, methodName="runTest"):
        super().__init__(methodName=methodName)
        self.handler = CookieRedirectHttpRequestHandler

    @classmethod
    def setUpClass(cls):
        key = rsa.generate_private_key(
            public_exponent=65537,
            key_size=2048,
        )

        with open(get_file("https_key.pem"), "wb") as f:
            f.write(key.private_bytes(
                encoding=serialization.Encoding.PEM,
                format=serialization.PrivateFormat.TraditionalOpenSSL,
                encryption_algorithm=serialization.NoEncryption(),
            ))

        subject = issuer = x509.Name([
            x509.NameAttribute(NameOID.ORGANIZATION_NAME, "LinkChecker"),
            x509.NameAttribute(NameOID.COMMON_NAME, "linkchecker.github.io"),
        ])

        cert = x509.CertificateBuilder().subject_name(
            subject
        ).issuer_name(
            issuer
        ).public_key(
            key.public_key()
        ).serial_number(
            x509.random_serial_number()
        ).not_valid_before(
            datetime.datetime.now(datetime.timezone.utc)
        ).not_valid_after(
            datetime.datetime(2119, 1, 2, 3, 4, 5)
        ).add_extension(
            x509.SubjectAlternativeName([x509.DNSName("localhost")]),
            critical=False,
        ).sign(key, hashes.SHA256())

        with open(get_file("https_cert.pem"), "wb") as f:
            f.write(cert.public_bytes(serialization.Encoding.PEM))

    def test_https(self):
        url = self.get_url("")
        resultlines = [
            "url %s" % url,
            "cache key %s" % url,
            "real url %s" % url,
            "valid",
        ]
        confargs = dict(sslverify=get_file("https_cert.pem"))
        with patch.dict("os.environ",
                        {"REQUESTS_CA_BUNDLE": get_file("https_cert.pem")}):
            self.direct(url, resultlines, recursionlevel=0, confargs=confargs)

    def test_x509_to_dict(self):
        with open(get_file("https_cert.pem"), "rb") as f:
            cert = crypto.load_certificate(crypto.FILETYPE_PEM, f.read())
        self.assertEqual(
            httputil.x509_to_dict(cert)["notAfter"], "Jan 02 03:04:05 2119 GMT"
        )
