"""

This module module is used to generate the CAs and CRLs (revoked certificates)

Example::

  from DIRAC.Core.Security import Utilities

  retVal = Utilities.generateRevokedCertsFile()
  if retVal['OK']:
    cl = Elasticsearch( self.__url,
                        timeout = self.__timeout,
                        use_ssl = True,
                        verify_certs = True,
                        ca_certs = retVal['Value'] )

or::

  retVal = Utilities.generateCAFile('/WebApp/HTTPS/Cert')
  if retVal['OK']:
    sslops = dict( certfile = CertificateMgmt.getCert(/WebApp/HTTPS/Cert),
                   keyfile = CertificateMgmt.getCert(/WebApp/HTTPS/Key),
                   cert_reqs = ssl.CERT_OPTIONAL,
                   ca_certs = retVal['Value'],
                   ssl_version = ssl.PROTOCOL_TLSv1 )

  srv = tornado.httpserver.HTTPServer( self.__app, ssl_options = sslops, xheaders = True )

Note: If you wan to make sure that the CA is up to date, better to use the BundleDeliveryClient.

"""
from __future__ import absolute_import
from __future__ import division
from __future__ import print_function
import os
import tempfile

from DIRAC.Core.Security import X509Chain, X509CRL
from DIRAC.Core.Security import Locations
from DIRAC import gLogger, S_OK, S_ERROR


def generateCAFile(location=None):
    """

    Generate/find a single CA file with all the PEMs

    :param str location: we can specify a specific CS location
                         where it's written a directory where to find the CAs and CRLs
    :return: directory where the file cas.pem which contains all certificates is found/created

    """
    caDir = Locations.getCAsLocation()
    if not caDir:
        return S_ERROR("No CAs dir found")

    # look in what's normally /etc/grid-security/certificates
    if os.path.isfile(os.path.join(os.path.dirname(caDir), "cas.pem")):
        return S_OK(os.path.join(os.path.dirname(caDir), "cas.pem"))

    # look in what's normally /opt/dirac/etc/grid-security
    diracCADirPEM = os.path.join(os.path.dirname(Locations.getHostCertificateAndKeyLocation(location)[0]), "cas.pem")
    if os.path.isfile(diracCADirPEM):
        return S_OK(diracCADirPEM)

    # Now we create it in tmpdir
    fn = tempfile.mkstemp(prefix="cas.", suffix=".pem")[1]
    try:
        with open(fn, "wb") as fd:
            for caFile in os.listdir(caDir):
                caFile = os.path.join(caDir, caFile)
                chain = X509Chain.X509Chain()
                result = chain.loadChainFromFile(caFile)
                if not result["OK"]:
                    continue

                expired = chain.hasExpired()
                if not expired["OK"] or expired["Value"]:
                    continue
                fd.write(chain.dumpAllToString()["Value"])

        gLogger.info("CAs used from: %s" % str(fn))
        return S_OK(fn)
    except IOError as err:
        gLogger.warn(err)

    return S_ERROR("Could not find/generate CAs")


def generateRevokedCertsFile(location=None):
    """

    Generate a single CA file with all the PEMs

    :param str location: we can specify a specific CS location
                         where it's written a directory where to find the CAs and CRLs
    :return: directory where the file crls.pem which contains all CRLs is created

    """
    caDir = Locations.getCAsLocation()
    if not caDir:
        return S_ERROR("No CAs dir found")

    # look in what's normally /etc/grid-security/certificates
    if os.path.isfile(os.path.join(os.path.dirname(caDir), "crls.pem")):
        return S_OK(os.path.join(os.path.dirname(caDir), "crls.pem"))

    # look in what's normally /opt/dirac/etc/grid-security
    diracCADirPEM = os.path.join(os.path.dirname(Locations.getHostCertificateAndKeyLocation(location)[0]), "crls.pem")
    if os.path.isfile(diracCADirPEM):
        return S_OK(diracCADirPEM)

    # Now we create it in tmpdir
    fn = tempfile.mkstemp(prefix="crls", suffix=".pem")[1]
    try:
        with open(fn, "wb") as fd:
            for caFile in os.listdir(caDir):
                caFile = os.path.join(caDir, caFile)
                result = X509CRL.X509CRL.instanceFromFile(caFile)
                if not result["OK"]:
                    continue
                chain = result["Value"]
                fd.write(chain.dumpAllToString()["Value"])
            return S_OK(fn)
    except IOError as err:
        gLogger.warn(err)

    return S_ERROR("Could not find/generate CRLs")
