# Path: src/sii/lib/helpers.py
# def prepend_dtd(xml):
#     """ Prepends a DTD providing a definition of a to a non-standard xml:id pointer. Necessary for
#     signature and signature verification.
# 
#     :param `etree.Element` xml: XML tree to prepend the DTD to.
# 
#     :param str sig_tag:   Tag name to contain the URI.
#     :param str uri_attr:  Attribute name to contain the URI.
# 
#     :return: An `etree.Element` with the now DTD contextualized XML.
#     """
#     root = None
#     if hasattr(xml, 'getroot'):
#         root = xml.getroot()
#     else:
#         root = xml.getroottree().getroot()
# 
#     tag      = re.sub('\{.*\}', '', root.tag)
#     preamble = DTD_PREAMBLE.format(root=tag)
# 
#     buff = io.BytesIO()
#     buff.write(bytes(preamble, 'utf8'))
#     buff.write(etree.tostring(xml, pretty_print=True, method='xml'))
#     buff.seek(0)
# 
#     tree = etree.parse(buff)
#     root = tree.getroot()
# 
#     return root
# 
# def extract_signode(xml):
#     """ Extracts the <ds:Signature> node from right under the root node in an XML document. If none
#     is found there, an RuntimeException gets risen.
# 
#     :param `etree.Element` xml: Root node of the document.
# 
#     :return: `etree.Element` of the <ds:Signature>
#     """
#     signode = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature')
# 
#     if signode is None:
#         raise ValueError("Did not find a '{http://www.w3.org/2000/09/xmldsig#}Signature' under the root node")
# 
#     return signode
# 
# def extract_signodes(xml):
#     """ Extracts all <ds:Signature> nodes from given XML.
# 
#     :param `etree.Element` xml: Root node of the document.
# 
#     :return: list of `etree.Element` of the <ds:Signature>'s
#     """
#     signodes = xml.xpath('//ds:Signature', namespaces={'ds': 'http://www.w3.org/2000/09/xmldsig#'})
#     return signodes


import xmlsec
from .helpers import prepend_dtd, extract_signode, extract_signodes
    signode = extract_signode(xml)

    # Load Private Key and Public Certificate
    key = xmlsec.Key.from_file(key_path, xmlsec.KeyFormat.PEM)
    key.load_cert_from_file(cert_path, xmlsec.KeyFormat.PEM)

    # Create Crypto Context and load in Key/Cert
    ctx     = xmlsec.SignatureContext()
    ctx.key = key

    ctx.sign(signode)

    return xml


def sign_document_all(xml, key_path, cert_path):
    """ Signs all XML's <ds:Signature> nodes under the document root node.

    :param `etree.Element` xml: The XML to be signed.

    :param str key_path:  Path to PEM key file.
    :param str cert_path: Path to PEM certificate file.

    :return: `etree.Element` to the signed document. Should be the same with the provided xml param.

    TODO: make sure we get all <ds:Signature> nodes in depth first order, otherwise we would break envolving
    signatures. Its not that it is not currently working, it is just without guaranteed order.
    """
    # HACK inject a DTD preamble in to direct non-standard xml:id
    # resolution for <Reference URI = "#XXXX">.

# Path: src/sii/lib/helpers.py
# def prepend_dtd(xml):
#     """ Prepends a DTD providing a definition of a to a non-standard xml:id pointer. Necessary for
#     signature and signature verification.
# 
#     :param `etree.Element` xml: XML tree to prepend the DTD to.
# 
#     :param str sig_tag:   Tag name to contain the URI.
#     :param str uri_attr:  Attribute name to contain the URI.
# 
#     :return: An `etree.Element` with the now DTD contextualized XML.
#     """
#     root = None
#     if hasattr(xml, 'getroot'):
#         root = xml.getroot()
#     else:
#         root = xml.getroottree().getroot()
# 
#     tag      = re.sub('\{.*\}', '', root.tag)
#     preamble = DTD_PREAMBLE.format(root=tag)
# 
#     buff = io.BytesIO()
#     buff.write(bytes(preamble, 'utf8'))
#     buff.write(etree.tostring(xml, pretty_print=True, method='xml'))
#     buff.seek(0)
# 
#     tree = etree.parse(buff)
#     root = tree.getroot()
# 
#     return root
# 
# def extract_signode(xml):
#     """ Extracts the <ds:Signature> node from right under the root node in an XML document. If none
#     is found there, an RuntimeException gets risen.
# 
#     :param `etree.Element` xml: Root node of the document.
# 
#     :return: `etree.Element` of the <ds:Signature>
#     """
#     signode = xml.find('{http://www.w3.org/2000/09/xmldsig#}Signature')
# 
#     if signode is None:
#         raise ValueError("Did not find a '{http://www.w3.org/2000/09/xmldsig#}Signature' under the root node")
# 
#     return signode
# 
# def extract_signodes(xml):
#     """ Extracts all <ds:Signature> nodes from given XML.
# 
#     :param `etree.Element` xml: Root node of the document.
# 
#     :return: list of `etree.Element` of the <ds:Signature>'s
#     """
#     signodes = xml.xpath('//ds:Signature', namespaces={'ds': 'http://www.w3.org/2000/09/xmldsig#'})
#     return signodes


# Path: src/sii/lib/signature.py
import xmlsec
from .helpers import prepend_dtd, extract_signode, extract_signodes

    signode = extract_signode(xml)

    # Load Private Key and Public Certificate
    key = xmlsec.Key.from_file(key_path, xmlsec.KeyFormat.PEM)
    key.load_cert_from_file(cert_path, xmlsec.KeyFormat.PEM)

    # Create Crypto Context and load in Key/Cert
    ctx     = xmlsec.SignatureContext()
    ctx.key = key

    ctx.sign(signode)

    return xml


def sign_document_all(xml, key_path, cert_path):
    """ Signs all XML's <ds:Signature> nodes under the document root node.

    :param `etree.Element` xml: The XML to be signed.

    :param str key_path:  Path to PEM key file.
    :param str cert_path: Path to PEM certificate file.

    :return: `etree.Element` to the signed document. Should be the same with the provided xml param.

    TODO: make sure we get all <ds:Signature> nodes in depth first order, otherwise we would break envolving
    signatures. Its not that it is not currently working, it is just without guaranteed order.
    """
    # HACK inject a DTD preamble in to direct non-standard xml:id
    # resolution for <Reference URI = "#XXXX">.

    xml = prepend_dtd(xml)