# -*- coding: utf-8 -*-

# Copyright 2012-2016 Mir Calculate. http://www.calculate-linux.org
#
#  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 sys
from M2Crypto import RSA, X509, EVP, m2
from calculate.lib.cl_lang import setLocalTranslate

_ = lambda x: x
setLocalTranslate('cl_core3', sys.modules[__name__])


def passphrase_callback(v):
    return None


def generateRSAKey():
    return RSA.gen_key(2048, m2.RSA_F4)


def makePKey(key):
    pkey = EVP.PKey()
    pkey.assign_rsa(key)
    return pkey


def makeRequest(pubkey, pkey, serv_host, port):
    """ create query to the signing on server """
    req = X509.Request()
    # Seems to default to 0, but we can now set it as well, so just API test
    req.set_version(req.get_version())
    req.set_pubkey(pkey)
    name = X509.X509_Name()
    c = raw_input(_("Enter the certificate date manually? [y]/n: "))
    if c.lower() in ['n', 'no']:
        name.CN = 'root_cert'  # (Common Name);
        name.OU = 'www.calculate-linux.ru'  # (Organization Unit);
        name.O = 'calculate-linux'  # (Organization Name);
        name.L = ''  # (Locality Name);
        name.ST = 'Spb'  # (State Name);
        name.C = 'En'  # (Country);
    else:
        import socket

        print _('Do not use spaces or tabs.')
        host_name = socket.getfqdn()
        # if serv_host == host_name:
        # print '\n'+_("Want to create self-signed certificate?\n"
        # "Use key --gen-cert-self")
        # return None
        if serv_host in host_name:
            host_name = host_name.replace('.' + serv_host, '')
            list_host_name = host_name.split('.')
            print 'list_host_name = ', list_host_name
            result_host_name = \
                list_host_name[len(list_host_name) - 1] + "." + serv_host
        else:
            host_name = socket.getfqdn()
            list_host_name = host_name.split('.')
            result_host_name = list_host_name[0] + "." + serv_host
        name.CN = raw_input(_('Hostname [%s] : ') % result_host_name)
        if name.CN in ['', None]:
            name.CN = result_host_name
        name.OU = raw_input(_('Organization unit: '))
        if not name.OU:
            name.OU = ''
        else:
            name.OU.replace(' ', '_').replace('\t', '_')
        name.O = raw_input(_('Organization name: '))
        if not name.O:
            name.O = ''
        else:
            name.O.replace(' ', '_').replace('\t', '_')
        network = _('Full network address (host:port)')
        name.L = raw_input(network + ' [%s:%d]: ' % (host_name, port))
        if name.L in ['', None]:
            name.L = host_name + ':' + str(port)
        name.ST = raw_input(_('City: '))
        if not name.ST:
            name.ST = ''
        else:
            name.ST.replace(' ', '_').replace('\t', '_')
        name.C = raw_input(_('Country (two letters only!): '))

    req.set_subject_name(name)
    # ext1 = X509.new_extension('nsComment', 'Hello there')
    ext1 = X509.new_extension('Comment', 'Auto Generated')
    extstack = X509.X509_Extension_Stack()
    extstack.push(ext1)
    req.add_extensions(extstack)
    req.sign(pkey, 'md5')
    return req


def makeCert(req, caPkey, issuer, client_cert=False, group=None):
    pkey = req.get_pubkey()
    # woop = makePKey(generateRSAKey())
    # if not req.verify(woop.pkey):
    if not req.verify(pkey):
        # XXX What error object should I use?
        raise ValueError('Error verifying request')
    sub = req.get_subject()
    # If this were a real certificate request, you would display
    # all the relevant data from the request and ask a human operator
    # if you were sure. Now we just create the certificate blindly based
    # on the request.    
    cert = X509.X509()
    # We know we are making CA cert now...
    # Serial defaults to 0.
    cert.set_serial_number(1)
    cert.set_version(2)
    cert.set_subject(sub)
    cert.set_issuer(issuer)
    cert.set_pubkey(pkey)
    notBefore = m2.x509_get_not_before(cert.x509)
    notAfter = m2.x509_get_not_after(cert.x509)
    m2.x509_gmtime_adj(notBefore, -1 * 60 * 60 * 24)
    days = 1095  # 3 year
    m2.x509_gmtime_adj(notAfter, 60 * 60 * 24 * days)

    if client_cert:
        cert.add_ext(X509.new_extension('basicConstraints', 'CA:FALSE'))
        cert.add_ext(X509.new_extension('nsCertType', 'client'))
        cert.add_ext(X509.new_extension('keyUsage',
                                        'digitalSignature, keyEncipherment'))
        cert.add_ext(X509.new_extension('extendedKeyUsage', 'clientAuth'))
        if group:
            cert.add_ext(X509.new_extension('nsComment', 'group:%s' % group))
    else:
        ext = X509.new_extension('basicConstraints', 'CA:TRUE')
        ext.set_critical(1)
        cert.add_ext(ext)

        # Create the subject key identifier
        # modulus = cert.get_pubkey().get_modulus()
        # sha_hash = hashlib.sha1(modulus).digest()
        # sub_key_id = ":".join(["%02X"%ord(byte) for byte in sha_hash])
        cert.add_ext(X509.new_extension('subjectKeyIdentifier', 'hash'))

        cert.add_ext(X509.new_extension('authorityKeyIdentifier', 'keyid'))
    cert.sign(caPkey, 'sha1')
    return cert
