From ef63d8fc66bb8a74d6ed24a0b0d0101579065752 Mon Sep 17 00:00:00 2001 From: Carl Meyer Date: Fri, 19 Jun 2015 19:03:25 -0600 Subject: [PATCH 001/378] Allow specifying a custom id attr for registering an ID. --- src/xmlsec/ds.pyx | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/xmlsec/ds.pyx b/src/xmlsec/ds.pyx index 2922c971..30c7680a 100644 --- a/src/xmlsec/ds.pyx +++ b/src/xmlsec/ds.pyx @@ -1,7 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division -from lxml.includes.tree cimport xmlHasProp, xmlAttr +from lxml.includes.tree cimport xmlHasProp, xmlHasNsProp, xmlAttr from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() @@ -55,11 +55,16 @@ cdef class SignatureContext(object): instance._handle = self._handle.signKey return instance - def register_id(self, _Element node not None): + def register_id(self, _Element node not None, id_attr="ID", id_ns=None): cdef xmlAttr* attr - attr = xmlHasProp(node._c_node, _b("ID")) - value = node.attrib.get("ID") + if id_ns: + attr = xmlHasNsProp(node._c_node, _b(id_attr), _b(id_ns)) + attrname = '{%s}%s' % (id_ns, id_attr) + else: + attr = xmlHasProp(node._c_node, _b(id_attr)) + attrname = id_attr + value = node.attrib.get(attrname) xmlAddID(NULL, node._doc._c_doc, _b(value), attr) From ea7615897a905f9b2838e58d98f9c235a9a4f155 Mon Sep 17 00:00:00 2001 From: Changje Jeong Date: Mon, 31 Aug 2015 11:55:57 +0900 Subject: [PATCH 002/378] Fix "error: lvalue required as left operand of assignment" error --- src/xmlsec/enc.pxd | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/xmlsec/enc.pxd b/src/xmlsec/enc.pxd index 2de629b1..78891651 100644 --- a/src/xmlsec/enc.pxd +++ b/src/xmlsec/enc.pxd @@ -3,9 +3,10 @@ from .key cimport xmlSecKeyPtr, xmlSecKeyReqPtr, xmlSecKeysMngrPtr from .ds cimport const_xmlSecByte, xmlSecBufferPtr -cdef extern from "xmlsec.h": # xmlsec/keys.h +cdef unsigned int XMLSEC_ENC_RETURN_REPLACED_NODE + - unsigned int XMLSEC_ENC_RETURN_REPLACED_NODE +cdef extern from "xmlsec.h": # xmlsec/keys.h cdef struct _xmlSecEncCtx: # void * userData From 946cbb83b26ea0d4b300ccf82f0ec414dc0d7eab Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 1 Sep 2015 22:33:59 +0300 Subject: [PATCH 003/378] optimize imports, fixed build with cython 0.23.1 --- src/xmlsec/constants.pyx | 3 +-- src/xmlsec/ds.pyx | 3 +-- src/xmlsec/enc.pxd | 2 +- src/xmlsec/enc.pyx | 8 +++----- src/xmlsec/key.pyx | 3 +-- src/xmlsec/template.pyx | 5 ++--- src/xmlsec/tree.pyx | 4 ++-- src/xmlsec/utils.pyx | 2 -- tests/examples/test_decrypt.py | 9 +++++++-- tests/examples/test_encrypt.py | 8 ++++++-- 10 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index 91b6b06a..75368126 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division -from .constants cimport * -from .utils cimport * +from .utils cimport _u __all__ = [ 'Namespace', diff --git a/src/xmlsec/ds.pyx b/src/xmlsec/ds.pyx index 30c7680a..7bb047fa 100644 --- a/src/xmlsec/ds.pyx +++ b/src/xmlsec/ds.pyx @@ -7,12 +7,11 @@ import_lxml__etree() from lxml.includes.etreepublic cimport _Element -from .ds cimport * from .constants cimport _Transform, xmlSecTransformUsageSignatureMethod from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy -from .error import * from .utils cimport _b +from .error import * __all__ = [ diff --git a/src/xmlsec/enc.pxd b/src/xmlsec/enc.pxd index 2de629b1..7c23fee3 100644 --- a/src/xmlsec/enc.pxd +++ b/src/xmlsec/enc.pxd @@ -5,7 +5,7 @@ from .ds cimport const_xmlSecByte, xmlSecBufferPtr cdef extern from "xmlsec.h": # xmlsec/keys.h - unsigned int XMLSEC_ENC_RETURN_REPLACED_NODE + cdef enum: XMLSEC_ENC_RETURN_REPLACED_NODE cdef struct _xmlSecEncCtx: # void * userData diff --git a/src/xmlsec/enc.pyx b/src/xmlsec/enc.pyx index bf970af5..33c1dcb6 100644 --- a/src/xmlsec/enc.pyx +++ b/src/xmlsec/enc.pyx @@ -5,18 +5,15 @@ from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() from lxml.includes.etreepublic cimport _Document, _Element, elementFactory -from lxml.includes.tree cimport xmlDocCopyNode, xmlFreeNode, xmlNode, xmlDoc, xmlDocGetRootElement +from lxml.includes.tree cimport xmlDocCopyNode, xmlFreeNode, xmlDoc, xmlDocGetRootElement -from .enc cimport * from .constants import EncryptionType -from .utils cimport * from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy - +from .utils cimport _b from .error import * from copy import copy - __all__ = [ 'EncryptionContext' ] @@ -47,6 +44,7 @@ cdef class EncryptionContext: raise InternalError("failed to create encryption context") self._handle = handle + print("!!!", XMLSEC_ENC_RETURN_REPLACED_NODE) def __dealloc__(self): if self._handle != NULL: diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index ae660be1..3acca163 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -1,8 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division -from .key cimport * -from .utils cimport * +from .utils cimport _b, _u from .error import * from copy import copy diff --git a/src/xmlsec/template.pyx b/src/xmlsec/template.pyx index 81435e9e..f6e2af9f 100644 --- a/src/xmlsec/template.pyx +++ b/src/xmlsec/template.pyx @@ -5,10 +5,9 @@ from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() from lxml.includes.etreepublic cimport _Element, elementFactory -from lxml.includes.tree cimport const_xmlChar, xmlNode, xmlStrdup +from lxml.includes.tree cimport xmlStrdup from .constants cimport _Transform -from .utils cimport * -from .template cimport * +from .utils cimport _b def create(_Element node not None, diff --git a/src/xmlsec/tree.pyx b/src/xmlsec/tree.pyx index 2cf7557d..7a4d648f 100644 --- a/src/xmlsec/tree.pyx +++ b/src/xmlsec/tree.pyx @@ -6,9 +6,9 @@ from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() from lxml.includes.etreepublic cimport _ElementTree, _Element, elementFactory -from .tree cimport * -from .utils cimport * from .constants import Namespace +from .utils cimport _b + __all__ = [ 'find_child', diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx index 8287bad1..5d0294cc 100644 --- a/src/xmlsec/utils.pyx +++ b/src/xmlsec/utils.pyx @@ -1,8 +1,6 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division -from .utils cimport * - __all__ = [ 'init', 'shutdown', diff --git a/tests/examples/test_decrypt.py b/tests/examples/test_decrypt.py index d9f45731..ba6e393e 100644 --- a/tests/examples/test_decrypt.py +++ b/tests/examples/test_decrypt.py @@ -1,12 +1,17 @@ +from __future__ import with_statement from os import path import xmlsec from .base import parse_xml, BASE_DIR, compare +def read_from_file(filename): + with open(filename, "rb") as stream: + return stream.read() + def test_decrypt1(): manager = xmlsec.KeysManager() filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_memory(open(filename, 'rb'), xmlsec.KeyFormat.PEM, None) + key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.PEM, None) assert key is not None manager.add_key(key) @@ -24,7 +29,7 @@ def test_decrypt1(): def test_decrypt2(): manager = xmlsec.KeysManager() filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_memory(open(filename, 'rb'), xmlsec.KeyFormat.PEM, None) + key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.PEM, None) assert key is not None manager.add_key(key) diff --git a/tests/examples/test_encrypt.py b/tests/examples/test_encrypt.py index 54b5d334..31eb0894 100644 --- a/tests/examples/test_encrypt.py +++ b/tests/examples/test_encrypt.py @@ -3,12 +3,16 @@ from .base import parse_xml, BASE_DIR from lxml import etree +def read_from_file(filename): + with open(filename, "rb") as stream: + return stream.read() + def test_encrypt_xml(): # Load the public cert manager = xmlsec.KeysManager() filename = path.join(BASE_DIR, 'rsacert.pem') - key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.CERT_PEM, None) + key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.CERT_PEM, None) assert key is not None manager.add_key(key) template = parse_xml('enc1-doc.xml') @@ -46,7 +50,7 @@ def test_encrypt_binary(): # Load the public cert manager = xmlsec.KeysManager() filename = path.join(BASE_DIR, 'rsacert.pem') - key = xmlsec.Key.from_memory(open(filename, 'rb').read(), xmlsec.KeyFormat.CERT_PEM, None) + key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.CERT_PEM, None) assert key is not None manager.add_key(key) template = etree.Element("root") From 0541f0914713443738c28cf15d8ed11effc33a11 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 1 Sep 2015 23:38:31 +0300 Subject: [PATCH 004/378] removed debug print --- src/xmlsec/enc.pyx | 1 - 1 file changed, 1 deletion(-) diff --git a/src/xmlsec/enc.pyx b/src/xmlsec/enc.pyx index 33c1dcb6..94435131 100644 --- a/src/xmlsec/enc.pyx +++ b/src/xmlsec/enc.pyx @@ -44,7 +44,6 @@ cdef class EncryptionContext: raise InternalError("failed to create encryption context") self._handle = handle - print("!!!", XMLSEC_ENC_RETURN_REPLACED_NODE) def __dealloc__(self): if self._handle != NULL: From a34f2fcd144ed43db379532b5465a986f948708a Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 3 Sep 2015 00:06:09 +0300 Subject: [PATCH 005/378] the cython older than 0.23 does not automatically include coresponding .pxd file --- src/xmlsec/constants.pyx | 1 + src/xmlsec/ds.pyx | 1 + src/xmlsec/enc.pyx | 4 +++- src/xmlsec/key.pyx | 1 + src/xmlsec/template.pyx | 1 + src/xmlsec/tree.pyx | 3 ++- src/xmlsec/utils.pyx | 2 ++ 7 files changed, 11 insertions(+), 2 deletions(-) diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index 75368126..032a6838 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division +from .constants cimport * from .utils cimport _u __all__ = [ diff --git a/src/xmlsec/ds.pyx b/src/xmlsec/ds.pyx index 7bb047fa..22ceb330 100644 --- a/src/xmlsec/ds.pyx +++ b/src/xmlsec/ds.pyx @@ -7,6 +7,7 @@ import_lxml__etree() from lxml.includes.etreepublic cimport _Element +from .ds cimport * from .constants cimport _Transform, xmlSecTransformUsageSignatureMethod from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy diff --git a/src/xmlsec/enc.pyx b/src/xmlsec/enc.pyx index 94435131..2ddbe319 100644 --- a/src/xmlsec/enc.pyx +++ b/src/xmlsec/enc.pyx @@ -7,10 +7,12 @@ import_lxml__etree() from lxml.includes.etreepublic cimport _Document, _Element, elementFactory from lxml.includes.tree cimport xmlDocCopyNode, xmlFreeNode, xmlDoc, xmlDocGetRootElement -from .constants import EncryptionType +from .enc cimport * from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy from .utils cimport _b + +from .constants import EncryptionType from .error import * from copy import copy diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 3acca163..503c4413 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -1,6 +1,7 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division +from .key cimport * from .utils cimport _b, _u from .error import * from copy import copy diff --git a/src/xmlsec/template.pyx b/src/xmlsec/template.pyx index f6e2af9f..37892196 100644 --- a/src/xmlsec/template.pyx +++ b/src/xmlsec/template.pyx @@ -4,6 +4,7 @@ from __future__ import absolute_import, unicode_literals, division from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() +from .template cimport * from lxml.includes.etreepublic cimport _Element, elementFactory from lxml.includes.tree cimport xmlStrdup from .constants cimport _Transform diff --git a/src/xmlsec/tree.pyx b/src/xmlsec/tree.pyx index 7a4d648f..42c47461 100644 --- a/src/xmlsec/tree.pyx +++ b/src/xmlsec/tree.pyx @@ -6,8 +6,9 @@ from lxml.includes.etreepublic cimport import_lxml__etree import_lxml__etree() from lxml.includes.etreepublic cimport _ElementTree, _Element, elementFactory -from .constants import Namespace +from .tree cimport * from .utils cimport _b +from .constants import Namespace __all__ = [ diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx index 5d0294cc..8287bad1 100644 --- a/src/xmlsec/utils.pyx +++ b/src/xmlsec/utils.pyx @@ -1,6 +1,8 @@ # -*- coding: utf-8 -*- from __future__ import absolute_import, unicode_literals, division +from .utils cimport * + __all__ = [ 'init', 'shutdown', From 6f7544579dbbd6ff214294b7d18c87640c35d1d6 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 6 Oct 2015 04:34:16 -0700 Subject: [PATCH 006/378] Revert "Fix "error: lvalue required as left operand of assignment" error" --- src/xmlsec/enc.pxd | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/xmlsec/enc.pxd b/src/xmlsec/enc.pxd index 78891651..2de629b1 100644 --- a/src/xmlsec/enc.pxd +++ b/src/xmlsec/enc.pxd @@ -3,11 +3,10 @@ from .key cimport xmlSecKeyPtr, xmlSecKeyReqPtr, xmlSecKeysMngrPtr from .ds cimport const_xmlSecByte, xmlSecBufferPtr -cdef unsigned int XMLSEC_ENC_RETURN_REPLACED_NODE - - cdef extern from "xmlsec.h": # xmlsec/keys.h + unsigned int XMLSEC_ENC_RETURN_REPLACED_NODE + cdef struct _xmlSecEncCtx: # void * userData unsigned int flags From 5f908edf7d476ce65392dfa413c5ae097013378d Mon Sep 17 00:00:00 2001 From: mehcode Date: Tue, 6 Oct 2015 04:39:25 -0700 Subject: [PATCH 007/378] Bump version --- src/xmlsec/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py index 91e6d3c5..58143716 100644 --- a/src/xmlsec/meta.py +++ b/src/xmlsec/meta.py @@ -1,2 +1,2 @@ -version = '0.3.1' +version = '0.3.2' description = 'Python bindings for the XML Security Library.' From 6a6c82971f79356372b53f738e6adc20e0cf18bb Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 6 Oct 2015 04:41:48 -0700 Subject: [PATCH 008/378] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5a4a18d..48012560 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ # python-xmlsec [![Build Status](https://travis-ci.org/mehcode/python-xmlsec.png?branch=master)](https://travis-ci.org/mehcode/python-xmlsec) -[![PyPi Version](https://pypip.in/v/xmlsec/badge.png)](https://pypi.python.org/pypi/xmlsec) -![PyPi Downloads](https://pypip.in/d/xmlsec/badge.png) +[![PyPi Version](httpshttps://img.shields.io/pypi/v/xmlsec.svg)](https://pypi.python.org/pypi/xmlsec) +![PyPi Downloads](https://img.shields.io/pypi/dm/xmlsec.svg) > Python bindings for the XML Security Library. ## Usage From 19025a284bef92702564fb50cfbdc36f46479a8f Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 6 Oct 2015 04:42:00 -0700 Subject: [PATCH 009/378] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 48012560..965b8aa6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # python-xmlsec [![Build Status](https://travis-ci.org/mehcode/python-xmlsec.png?branch=master)](https://travis-ci.org/mehcode/python-xmlsec) -[![PyPi Version](httpshttps://img.shields.io/pypi/v/xmlsec.svg)](https://pypi.python.org/pypi/xmlsec) +[![PyPi Version](https://img.shields.io/pypi/v/xmlsec.svg)](https://pypi.python.org/pypi/xmlsec) ![PyPi Downloads](https://img.shields.io/pypi/dm/xmlsec.svg) > Python bindings for the XML Security Library. From b9dc625b01e57d69899b35701d930b4104641706 Mon Sep 17 00:00:00 2001 From: mehcode Date: Tue, 6 Oct 2015 04:42:21 -0700 Subject: [PATCH 010/378] Bump version --- src/xmlsec/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py index 58143716..32b168c9 100644 --- a/src/xmlsec/meta.py +++ b/src/xmlsec/meta.py @@ -1,2 +1,2 @@ -version = '0.3.2' +version = '0.3.3' description = 'Python bindings for the XML Security Library.' From dd97402a69a55b64f04dfc91aa7f67ed65d4b936 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 7 Oct 2015 13:21:07 +0300 Subject: [PATCH 011/378] Translated macroses to normal c-functions --- src/xmlsec/constants.pxd | 100 +++++++++++++++++++------------------- src/xmlsec/constants.pyx | 102 +++++++++++++++++++-------------------- src/xmlsec/key.pxd | 24 ++++----- src/xmlsec/key.pyx | 24 ++++----- 4 files changed, 125 insertions(+), 125 deletions(-) diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd index 5fa20306..8d6284eb 100644 --- a/src/xmlsec/constants.pxd +++ b/src/xmlsec/constants.pxd @@ -62,57 +62,57 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h ctypedef _xmlSecTransformKlass *xmlSecTransformId - xmlSecTransformId xmlSecTransformInclC14NId - xmlSecTransformId xmlSecTransformInclC14NWithCommentsId - xmlSecTransformId xmlSecTransformInclC14N11Id - xmlSecTransformId xmlSecTransformInclC14N11WithCommentsId - xmlSecTransformId xmlSecTransformExclC14NId - xmlSecTransformId xmlSecTransformExclC14NWithCommentsId - xmlSecTransformId xmlSecTransformEnvelopedId - xmlSecTransformId xmlSecTransformXPathId - xmlSecTransformId xmlSecTransformXPath2Id - xmlSecTransformId xmlSecTransformXPointerId - xmlSecTransformId xmlSecTransformXsltId - xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NId - xmlSecTransformId xmlSecTransformVisa3DHackId + xmlSecTransformId xmlSecTransformInclC14NGetKlass() + xmlSecTransformId xmlSecTransformInclC14NWithCommentsGetKlass() + xmlSecTransformId xmlSecTransformInclC14N11GetKlass() + xmlSecTransformId xmlSecTransformInclC14N11WithCommentsGetKlass() + xmlSecTransformId xmlSecTransformExclC14NGetKlass() + xmlSecTransformId xmlSecTransformExclC14NWithCommentsGetKlass() + xmlSecTransformId xmlSecTransformEnvelopedGetKlass() + xmlSecTransformId xmlSecTransformXPathGetKlass() + xmlSecTransformId xmlSecTransformXPath2GetKlass() + xmlSecTransformId xmlSecTransformXPointerGetKlass() + xmlSecTransformId xmlSecTransformXsltGetKlass() + xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NGetKlass() + xmlSecTransformId xmlSecTransformVisa3DHackGetKlass() - xmlSecTransformId xmlSecTransformAes128CbcId - xmlSecTransformId xmlSecTransformAes192CbcId - xmlSecTransformId xmlSecTransformAes256CbcId - xmlSecTransformId xmlSecTransformKWAes128Id - xmlSecTransformId xmlSecTransformKWAes192Id - xmlSecTransformId xmlSecTransformKWAes256Id - xmlSecTransformId xmlSecTransformDes3CbcId - xmlSecTransformId xmlSecTransformKWDes3Id - xmlSecTransformId xmlSecTransformDsaSha1Id - xmlSecTransformId xmlSecTransformEcdsaSha1Id - xmlSecTransformId xmlSecTransformEcdsaSha224Id - xmlSecTransformId xmlSecTransformEcdsaSha256Id - xmlSecTransformId xmlSecTransformEcdsaSha384Id - xmlSecTransformId xmlSecTransformEcdsaSha512Id - xmlSecTransformId xmlSecTransformHmacMd5Id - xmlSecTransformId xmlSecTransformHmacRipemd160Id - xmlSecTransformId xmlSecTransformHmacSha1Id - xmlSecTransformId xmlSecTransformHmacSha224Id - xmlSecTransformId xmlSecTransformHmacSha256Id - xmlSecTransformId xmlSecTransformHmacSha384Id - xmlSecTransformId xmlSecTransformHmacSha512Id - xmlSecTransformId xmlSecTransformMd5Id - xmlSecTransformId xmlSecTransformRipemd160Id - xmlSecTransformId xmlSecTransformRsaMd5Id - xmlSecTransformId xmlSecTransformRsaRipemd160Id - xmlSecTransformId xmlSecTransformRsaSha1Id - xmlSecTransformId xmlSecTransformRsaSha224Id - xmlSecTransformId xmlSecTransformRsaSha256Id - xmlSecTransformId xmlSecTransformRsaSha384Id - xmlSecTransformId xmlSecTransformRsaSha512Id - xmlSecTransformId xmlSecTransformRsaPkcs1Id - xmlSecTransformId xmlSecTransformRsaOaepId - xmlSecTransformId xmlSecTransformSha1Id - xmlSecTransformId xmlSecTransformSha224Id - xmlSecTransformId xmlSecTransformSha256Id - xmlSecTransformId xmlSecTransformSha384Id - xmlSecTransformId xmlSecTransformSha512Id + xmlSecTransformId xmlSecTransformAes128CbcGetKlass() + xmlSecTransformId xmlSecTransformAes192CbcGetKlass() + xmlSecTransformId xmlSecTransformAes256CbcGetKlass() + xmlSecTransformId xmlSecTransformKWAes128GetKlass() + xmlSecTransformId xmlSecTransformKWAes192GetKlass() + xmlSecTransformId xmlSecTransformKWAes256GetKlass() + xmlSecTransformId xmlSecTransformDes3CbcGetKlass() + xmlSecTransformId xmlSecTransformKWDes3GetKlass() + xmlSecTransformId xmlSecTransformDsaSha1GetKlass() + xmlSecTransformId xmlSecTransformEcdsaSha1GetKlass() + xmlSecTransformId xmlSecTransformEcdsaSha224GetKlass() + xmlSecTransformId xmlSecTransformEcdsaSha256GetKlass() + xmlSecTransformId xmlSecTransformEcdsaSha384GetKlass() + xmlSecTransformId xmlSecTransformEcdsaSha512GetKlass() + xmlSecTransformId xmlSecTransformHmacMd5GetKlass() + xmlSecTransformId xmlSecTransformHmacRipemd160GetKlass() + xmlSecTransformId xmlSecTransformHmacSha1GetKlass() + xmlSecTransformId xmlSecTransformHmacSha224GetKlass() + xmlSecTransformId xmlSecTransformHmacSha256GetKlass() + xmlSecTransformId xmlSecTransformHmacSha384GetKlass() + xmlSecTransformId xmlSecTransformHmacSha512GetKlass() + xmlSecTransformId xmlSecTransformMd5GetKlass() + xmlSecTransformId xmlSecTransformRipemd160GetKlass() + xmlSecTransformId xmlSecTransformRsaMd5GetKlass() + xmlSecTransformId xmlSecTransformRsaRipemd160GetKlass() + xmlSecTransformId xmlSecTransformRsaSha1GetKlass() + xmlSecTransformId xmlSecTransformRsaSha224GetKlass() + xmlSecTransformId xmlSecTransformRsaSha256GetKlass() + xmlSecTransformId xmlSecTransformRsaSha384GetKlass() + xmlSecTransformId xmlSecTransformRsaSha512GetKlass() + xmlSecTransformId xmlSecTransformRsaPkcs1GetKlass() + xmlSecTransformId xmlSecTransformRsaOaepGetKlass() + xmlSecTransformId xmlSecTransformSha1GetKlass() + xmlSecTransformId xmlSecTransformSha224GetKlass() + xmlSecTransformId xmlSecTransformSha256GetKlass() + xmlSecTransformId xmlSecTransformSha384GetKlass() + xmlSecTransformId xmlSecTransformSha512GetKlass() cdef class _Transform(object): diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index 032a6838..725b9d22 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -79,54 +79,54 @@ cdef _Transform _mkti(xmlSecTransformId target): class Transform: """Transform identifiers.""" - C14N = _mkti(xmlSecTransformInclC14NId) - C14N_COMMENTS = _mkti(xmlSecTransformInclC14NWithCommentsId) - C14N11 = _mkti(xmlSecTransformInclC14N11Id) - C14N11_COMMENTS = _mkti(xmlSecTransformInclC14N11WithCommentsId) - EXCL_C14N = _mkti(xmlSecTransformExclC14NId) - EXCL_C14N_COMMENTS = _mkti(xmlSecTransformExclC14NWithCommentsId) - ENVELOPED = _mkti(xmlSecTransformEnvelopedId) - XPATH = _mkti(xmlSecTransformXPathId) - XPATH2 = _mkti(xmlSecTransformXPath2Id) - XPOINTER = _mkti(xmlSecTransformXPointerId) - XSLT = _mkti(xmlSecTransformXsltId) - REMOVE_XML_TAGS_C14N = _mkti(xmlSecTransformRemoveXmlTagsC14NId) - VISA3D_HACK = _mkti(xmlSecTransformVisa3DHackId) - - AES128 = _mkti(xmlSecTransformAes128CbcId) - AES192 = _mkti(xmlSecTransformAes192CbcId) - AES256 = _mkti(xmlSecTransformAes256CbcId) - KW_AES128 = _mkti(xmlSecTransformKWAes128Id) - KW_AES192 = _mkti(xmlSecTransformKWAes192Id) - KW_AES256 = _mkti(xmlSecTransformKWAes256Id) - DES3 = _mkti(xmlSecTransformDes3CbcId) - KW_DES3 = _mkti(xmlSecTransformKWDes3Id) - DSA_SHA1 = _mkti(xmlSecTransformDsaSha1Id) - ECDSA_SHA1 = _mkti(xmlSecTransformEcdsaSha1Id) - ECDSA_SHA224 = _mkti(xmlSecTransformEcdsaSha224Id) - ECDSA_SHA256 = _mkti(xmlSecTransformEcdsaSha256Id) - ECDSA_SHA384 = _mkti(xmlSecTransformEcdsaSha384Id) - ECDSA_SHA512 = _mkti(xmlSecTransformEcdsaSha512Id) - HMAC_MD5 = _mkti(xmlSecTransformHmacMd5Id) - HMAC_RIPEMD160 = _mkti(xmlSecTransformHmacRipemd160Id) - HMAC_SHA1 = _mkti(xmlSecTransformHmacSha1Id) - HMAC_SHA224 = _mkti(xmlSecTransformHmacSha224Id) - HMAC_SHA256 = _mkti(xmlSecTransformHmacSha256Id) - HMAC_SHA384 = _mkti(xmlSecTransformHmacSha384Id) - HMAC_SHA512 = _mkti(xmlSecTransformHmacSha512Id) - MD5 = _mkti(xmlSecTransformMd5Id) - RIPEMD160 = _mkti(xmlSecTransformRipemd160Id) - RSA_MD5 = _mkti(xmlSecTransformRsaMd5Id) - RSA_RIPEMD160 = _mkti(xmlSecTransformRsaRipemd160Id) - RSA_SHA1 = _mkti(xmlSecTransformRsaSha1Id) - RSA_SHA224 = _mkti(xmlSecTransformRsaSha224Id) - RSA_SHA256 = _mkti(xmlSecTransformRsaSha256Id) - RSA_SHA384 = _mkti(xmlSecTransformRsaSha384Id) - RSA_SHA512 = _mkti(xmlSecTransformRsaSha512Id) - RSA_PKCS1 = _mkti(xmlSecTransformRsaPkcs1Id) - RSA_OAEP = _mkti(xmlSecTransformRsaOaepId) - SHA1 = _mkti(xmlSecTransformSha1Id) - SHA224 = _mkti(xmlSecTransformSha224Id) - SHA256 = _mkti(xmlSecTransformSha256Id) - SHA384 = _mkti(xmlSecTransformSha384Id) - SHA512 = _mkti(xmlSecTransformSha512Id) + C14N = _mkti(xmlSecTransformInclC14NGetKlass()) + C14N_COMMENTS = _mkti(xmlSecTransformInclC14NWithCommentsGetKlass()) + C14N11 = _mkti(xmlSecTransformInclC14N11GetKlass()) + C14N11_COMMENTS = _mkti(xmlSecTransformInclC14N11WithCommentsGetKlass()) + EXCL_C14N = _mkti(xmlSecTransformExclC14NGetKlass()) + EXCL_C14N_COMMENTS = _mkti(xmlSecTransformExclC14NWithCommentsGetKlass()) + ENVELOPED = _mkti(xmlSecTransformEnvelopedGetKlass()) + XPATH = _mkti(xmlSecTransformXPathGetKlass()) + XPATH2 = _mkti(xmlSecTransformXPath2GetKlass()) + XPOINTER = _mkti(xmlSecTransformXPointerGetKlass()) + XSLT = _mkti(xmlSecTransformXsltGetKlass()) + REMOVE_XML_TAGS_C14N = _mkti(xmlSecTransformRemoveXmlTagsC14NGetKlass()) + VISA3D_HACK = _mkti(xmlSecTransformVisa3DHackGetKlass()) + + AES128 = _mkti(xmlSecTransformAes128CbcGetKlass()) + AES192 = _mkti(xmlSecTransformAes192CbcGetKlass()) + AES256 = _mkti(xmlSecTransformAes256CbcGetKlass()) + KW_AES128 = _mkti(xmlSecTransformKWAes128GetKlass()) + KW_AES192 = _mkti(xmlSecTransformKWAes192GetKlass()) + KW_AES256 = _mkti(xmlSecTransformKWAes256GetKlass()) + DES3 = _mkti(xmlSecTransformDes3CbcGetKlass()) + KW_DES3 = _mkti(xmlSecTransformKWDes3GetKlass()) + DSA_SHA1 = _mkti(xmlSecTransformDsaSha1GetKlass()) + ECDSA_SHA1 = _mkti(xmlSecTransformEcdsaSha1GetKlass()) + ECDSA_SHA224 = _mkti(xmlSecTransformEcdsaSha224GetKlass()) + ECDSA_SHA256 = _mkti(xmlSecTransformEcdsaSha256GetKlass()) + ECDSA_SHA384 = _mkti(xmlSecTransformEcdsaSha384GetKlass()) + ECDSA_SHA512 = _mkti(xmlSecTransformEcdsaSha512GetKlass()) + HMAC_MD5 = _mkti(xmlSecTransformHmacMd5GetKlass()) + HMAC_RIPEMD160 = _mkti(xmlSecTransformHmacRipemd160GetKlass()) + HMAC_SHA1 = _mkti(xmlSecTransformHmacSha1GetKlass()) + HMAC_SHA224 = _mkti(xmlSecTransformHmacSha224GetKlass()) + HMAC_SHA256 = _mkti(xmlSecTransformHmacSha256GetKlass()) + HMAC_SHA384 = _mkti(xmlSecTransformHmacSha384GetKlass()) + HMAC_SHA512 = _mkti(xmlSecTransformHmacSha512GetKlass()) + MD5 = _mkti(xmlSecTransformMd5GetKlass()) + RIPEMD160 = _mkti(xmlSecTransformRipemd160GetKlass()) + RSA_MD5 = _mkti(xmlSecTransformRsaMd5GetKlass()) + RSA_RIPEMD160 = _mkti(xmlSecTransformRsaRipemd160GetKlass()) + RSA_SHA1 = _mkti(xmlSecTransformRsaSha1GetKlass()) + RSA_SHA224 = _mkti(xmlSecTransformRsaSha224GetKlass()) + RSA_SHA256 = _mkti(xmlSecTransformRsaSha256GetKlass()) + RSA_SHA384 = _mkti(xmlSecTransformRsaSha384GetKlass()) + RSA_SHA512 = _mkti(xmlSecTransformRsaSha512GetKlass()) + RSA_PKCS1 = _mkti(xmlSecTransformRsaPkcs1GetKlass()) + RSA_OAEP = _mkti(xmlSecTransformRsaOaepGetKlass()) + SHA1 = _mkti(xmlSecTransformSha1GetKlass()) + SHA224 = _mkti(xmlSecTransformSha224GetKlass()) + SHA256 = _mkti(xmlSecTransformSha256GetKlass()) + SHA384 = _mkti(xmlSecTransformSha384GetKlass()) + SHA512 = _mkti(xmlSecTransformSha512GetKlass()) diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index 8b06f75c..55c876de 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -14,18 +14,18 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h ctypedef _xmlSecKeyDataKlass *xmlSecKeyDataId - xmlSecKeyDataId xmlSecKeyDataNameId - xmlSecKeyDataId xmlSecKeyDataValueId - xmlSecKeyDataId xmlSecKeyDataRetrievalMethodId - xmlSecKeyDataId xmlSecKeyDataEncryptedKeyId - xmlSecKeyDataId xmlSecKeyDataAesId - xmlSecKeyDataId xmlSecKeyDataDesId - xmlSecKeyDataId xmlSecKeyDataDsaId - xmlSecKeyDataId xmlSecKeyDataEcdsaId - xmlSecKeyDataId xmlSecKeyDataHmacId - xmlSecKeyDataId xmlSecKeyDataRsaId - xmlSecKeyDataId xmlSecKeyDataX509Id - xmlSecKeyDataId xmlSecKeyDataRawX509CertId + xmlSecKeyDataId xmlSecKeyDataNameGetKlass() + xmlSecKeyDataId xmlSecKeyDataValueGetKlass() + xmlSecKeyDataId xmlSecKeyDataRetrievalMethodGetKlass() + xmlSecKeyDataId xmlSecKeyDataEncryptedKeyGetKlass() + xmlSecKeyDataId xmlSecKeyDataAesGetKlass() + xmlSecKeyDataId xmlSecKeyDataDesGetKlass() + xmlSecKeyDataId xmlSecKeyDataDsaGetKlass() + xmlSecKeyDataId xmlSecKeyDataEcdsaGetKlass() + xmlSecKeyDataId xmlSecKeyDataHmacGetKlass() + xmlSecKeyDataId xmlSecKeyDataRsaGetKlass() + xmlSecKeyDataId xmlSecKeyDataX509GetKlass() + xmlSecKeyDataId xmlSecKeyDataRawX509CertGetKlass() ctypedef enum xmlSecKeyDataFormat: xmlSecKeyDataFormatUnknown = 0 diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 503c4413..8cf00107 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -44,18 +44,18 @@ cdef _KeyData _mkkdi(xmlSecKeyDataId target): cdef class KeyData(object): - NAME = _mkkdi(xmlSecKeyDataNameId) - VALUE = _mkkdi(xmlSecKeyDataValueId) - RETRIEVALMETHOD = _mkkdi(xmlSecKeyDataRetrievalMethodId) - ENCRYPTEDKEY = _mkkdi(xmlSecKeyDataEncryptedKeyId) - AES = _mkkdi(xmlSecKeyDataAesId) - DES = _mkkdi(xmlSecKeyDataDesId) - DSA = _mkkdi(xmlSecKeyDataDsaId) - ECDSA = _mkkdi(xmlSecKeyDataEcdsaId) - HMAC = _mkkdi(xmlSecKeyDataHmacId) - RSA = _mkkdi(xmlSecKeyDataRsaId) - X509 = _mkkdi(xmlSecKeyDataX509Id) - RAWX509CERT = _mkkdi(xmlSecKeyDataRawX509CertId) + NAME = _mkkdi(xmlSecKeyDataNameGetKlass()) + VALUE = _mkkdi(xmlSecKeyDataValueGetKlass()) + RETRIEVALMETHOD = _mkkdi(xmlSecKeyDataRetrievalMethodGetKlass()) + ENCRYPTEDKEY = _mkkdi(xmlSecKeyDataEncryptedKeyGetKlass()) + AES = _mkkdi(xmlSecKeyDataAesGetKlass()) + DES = _mkkdi(xmlSecKeyDataDesGetKlass()) + DSA = _mkkdi(xmlSecKeyDataDsaGetKlass()) + ECDSA = _mkkdi(xmlSecKeyDataEcdsaGetKlass()) + HMAC = _mkkdi(xmlSecKeyDataHmacGetKlass()) + RSA = _mkkdi(xmlSecKeyDataRsaGetKlass()) + X509 = _mkkdi(xmlSecKeyDataX509GetKlass()) + RAWX509CERT = _mkkdi(xmlSecKeyDataRawX509CertGetKlass()) From 767510d5a5e932dbb5b9647ee5716dd2fbfadd1d Mon Sep 17 00:00:00 2001 From: mehcode Date: Tue, 27 Oct 2015 19:59:31 -0700 Subject: [PATCH 012/378] Use addons:apt --- .travis.yml | 16 ++++++++-------- setup.py | 2 ++ 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3bc78c85..971fe02f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,14 +4,14 @@ python: - '3.3' - '3.4' -before_install: - - 'travis_retry sudo apt-get update' - - 'travis_retry sudo apt-get install --fix-missing -y python-dev libxslt1-dev libssl-dev' - - 'travis_retry pip install Cython --use-mirrors' - - 'travis_retry wget -O /dev/stdout https://www.aleksey.com/xmlsec/download/xmlsec1-1.2.20.tar.gz | tar xzv' - - 'cd xmlsec1-1.2.20 && ./configure && make && sudo make install && sudo ldconfig && cd ..' +addons: + apt: + packages: + - libxslt1-dev + - libssl-dev + - libxmlsec1-dev install: - - 'travis_retry pip install -e ".[test]" --use-mirrors' + - travis_retry pip install -e ".[test]" -script: 'py.test' +script: py.test diff --git a/setup.py b/setup.py index 43c6074a..d2860b4c 100644 --- a/setup.py +++ b/setup.py @@ -92,7 +92,9 @@ def make_extension(name, cython=True): 'Operating System :: OS Independent', 'Programming Language :: Cython', 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', + 'Programming Language :: Python :: 3.4', 'Topic :: Text Processing :: Markup :: XML' ], author='Ryan Leckey', From 6bb16281bc93ea6a75f292b789a4601e6d7653fc Mon Sep 17 00:00:00 2001 From: mehcode Date: Tue, 27 Oct 2015 20:11:42 -0700 Subject: [PATCH 013/378] Need a newer version of libxmlsec1-dev then percise provides --- .travis.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 971fe02f..1ffe9414 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,11 @@ addons: packages: - libxslt1-dev - libssl-dev - - libxmlsec1-dev + +# Not sure how to install a more recent version of this +before_install: + - travis_retry wget -O /dev/stdout http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.20.tar.gz | tar xzv + - cd xmlsec1-1.2.20 && ./configure && make && sudo make install && sudo ldconfig && cd .. install: - travis_retry pip install -e ".[test]" From 2d94f9397be995b6c66a6d9ae8d1e012457f0901 Mon Sep 17 00:00:00 2001 From: mehcode Date: Tue, 27 Oct 2015 20:30:07 -0700 Subject: [PATCH 014/378] www.aleksey.com needs to fix their certificates --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 1ffe9414..ae7e6f92 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ addons: # Not sure how to install a more recent version of this before_install: - - travis_retry wget -O /dev/stdout http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.20.tar.gz | tar xzv + - travis_retry wget --no-check-certificate -O /dev/stdout http://www.aleksey.com/xmlsec/download/xmlsec1-1.2.20.tar.gz | tar xzv - cd xmlsec1-1.2.20 && ./configure && make && sudo make install && sudo ldconfig && cd .. install: From 4d1977fe3a6c35092065a4ae8b9523f7b5e80120 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 5 Nov 2015 18:30:17 +0300 Subject: [PATCH 015/378] Enhansments * Update travis.yaml to use docker-containers. * Use apt-get to install libxmlsec1 instead of downloading source-code. * Add nogil to c-functions --- .travis.yml | 12 ++-- src/xmlsec.h | 1 + src/xmlsec/constants.pxd | 102 ++++++++++++++++----------------- src/xmlsec/key.pxd | 24 ++++---- src/xmlsec/tree.pxd | 6 +- tests/examples/test_decrypt.py | 1 + tests/examples/test_encrypt.py | 3 +- 7 files changed, 76 insertions(+), 73 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3bc78c85..237bae9f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,15 +1,15 @@ +sudo: false language: python python: - '2.7' - '3.3' - '3.4' -before_install: - - 'travis_retry sudo apt-get update' - - 'travis_retry sudo apt-get install --fix-missing -y python-dev libxslt1-dev libssl-dev' - - 'travis_retry pip install Cython --use-mirrors' - - 'travis_retry wget -O /dev/stdout https://www.aleksey.com/xmlsec/download/xmlsec1-1.2.20.tar.gz | tar xzv' - - 'cd xmlsec1-1.2.20 && ./configure && make && sudo make install && sudo ldconfig && cd ..' +addons: + apt: + packages: + libxmlsec1 + libxmlsec1-openssl install: - 'travis_retry pip install -e ".[test]" --use-mirrors' diff --git a/src/xmlsec.h b/src/xmlsec.h index 6d741375..e03abd21 100644 --- a/src/xmlsec.h +++ b/src/xmlsec.h @@ -1,3 +1,4 @@ +#include #include #include #include diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd index 8d6284eb..e1be9c75 100644 --- a/src/xmlsec/constants.pxd +++ b/src/xmlsec/constants.pxd @@ -54,7 +54,7 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h xmlSecTransformUsageEncryptionMethod=0x0010 xmlSecTransformUsageAny=0xFFFF - # Transform ids + # Transform ids # xmlsec/app.h cdef struct _xmlSecTransformKlass: const_xmlChar* name const_xmlChar* href @@ -62,57 +62,57 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h ctypedef _xmlSecTransformKlass *xmlSecTransformId - xmlSecTransformId xmlSecTransformInclC14NGetKlass() - xmlSecTransformId xmlSecTransformInclC14NWithCommentsGetKlass() - xmlSecTransformId xmlSecTransformInclC14N11GetKlass() - xmlSecTransformId xmlSecTransformInclC14N11WithCommentsGetKlass() - xmlSecTransformId xmlSecTransformExclC14NGetKlass() - xmlSecTransformId xmlSecTransformExclC14NWithCommentsGetKlass() - xmlSecTransformId xmlSecTransformEnvelopedGetKlass() - xmlSecTransformId xmlSecTransformXPathGetKlass() - xmlSecTransformId xmlSecTransformXPath2GetKlass() - xmlSecTransformId xmlSecTransformXPointerGetKlass() - xmlSecTransformId xmlSecTransformXsltGetKlass() - xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NGetKlass() - xmlSecTransformId xmlSecTransformVisa3DHackGetKlass() + xmlSecTransformId xmlSecTransformInclC14NGetKlass() nogil + xmlSecTransformId xmlSecTransformInclC14NWithCommentsGetKlass() nogil + xmlSecTransformId xmlSecTransformInclC14N11GetKlass() nogil + xmlSecTransformId xmlSecTransformInclC14N11WithCommentsGetKlass() nogil + xmlSecTransformId xmlSecTransformExclC14NGetKlass() nogil + xmlSecTransformId xmlSecTransformExclC14NWithCommentsGetKlass() nogil + xmlSecTransformId xmlSecTransformEnvelopedGetKlass() nogil + xmlSecTransformId xmlSecTransformXPathGetKlass() nogil + xmlSecTransformId xmlSecTransformXPath2GetKlass() nogil + xmlSecTransformId xmlSecTransformXPointerGetKlass() nogil + xmlSecTransformId xmlSecTransformXsltGetKlass() nogil + xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NGetKlass() nogil + xmlSecTransformId xmlSecTransformVisa3DHackGetKlass() nogil - xmlSecTransformId xmlSecTransformAes128CbcGetKlass() - xmlSecTransformId xmlSecTransformAes192CbcGetKlass() - xmlSecTransformId xmlSecTransformAes256CbcGetKlass() - xmlSecTransformId xmlSecTransformKWAes128GetKlass() - xmlSecTransformId xmlSecTransformKWAes192GetKlass() - xmlSecTransformId xmlSecTransformKWAes256GetKlass() - xmlSecTransformId xmlSecTransformDes3CbcGetKlass() - xmlSecTransformId xmlSecTransformKWDes3GetKlass() - xmlSecTransformId xmlSecTransformDsaSha1GetKlass() - xmlSecTransformId xmlSecTransformEcdsaSha1GetKlass() - xmlSecTransformId xmlSecTransformEcdsaSha224GetKlass() - xmlSecTransformId xmlSecTransformEcdsaSha256GetKlass() - xmlSecTransformId xmlSecTransformEcdsaSha384GetKlass() - xmlSecTransformId xmlSecTransformEcdsaSha512GetKlass() - xmlSecTransformId xmlSecTransformHmacMd5GetKlass() - xmlSecTransformId xmlSecTransformHmacRipemd160GetKlass() - xmlSecTransformId xmlSecTransformHmacSha1GetKlass() - xmlSecTransformId xmlSecTransformHmacSha224GetKlass() - xmlSecTransformId xmlSecTransformHmacSha256GetKlass() - xmlSecTransformId xmlSecTransformHmacSha384GetKlass() - xmlSecTransformId xmlSecTransformHmacSha512GetKlass() - xmlSecTransformId xmlSecTransformMd5GetKlass() - xmlSecTransformId xmlSecTransformRipemd160GetKlass() - xmlSecTransformId xmlSecTransformRsaMd5GetKlass() - xmlSecTransformId xmlSecTransformRsaRipemd160GetKlass() - xmlSecTransformId xmlSecTransformRsaSha1GetKlass() - xmlSecTransformId xmlSecTransformRsaSha224GetKlass() - xmlSecTransformId xmlSecTransformRsaSha256GetKlass() - xmlSecTransformId xmlSecTransformRsaSha384GetKlass() - xmlSecTransformId xmlSecTransformRsaSha512GetKlass() - xmlSecTransformId xmlSecTransformRsaPkcs1GetKlass() - xmlSecTransformId xmlSecTransformRsaOaepGetKlass() - xmlSecTransformId xmlSecTransformSha1GetKlass() - xmlSecTransformId xmlSecTransformSha224GetKlass() - xmlSecTransformId xmlSecTransformSha256GetKlass() - xmlSecTransformId xmlSecTransformSha384GetKlass() - xmlSecTransformId xmlSecTransformSha512GetKlass() + xmlSecTransformId xmlSecTransformAes128CbcGetKlass() nogil + xmlSecTransformId xmlSecTransformAes192CbcGetKlass() nogil + xmlSecTransformId xmlSecTransformAes256CbcGetKlass() nogil + xmlSecTransformId xmlSecTransformKWAes128GetKlass() nogil + xmlSecTransformId xmlSecTransformKWAes192GetKlass() nogil + xmlSecTransformId xmlSecTransformKWAes256GetKlass() nogil + xmlSecTransformId xmlSecTransformDes3CbcGetKlass() nogil + xmlSecTransformId xmlSecTransformKWDes3GetKlass() nogil + xmlSecTransformId xmlSecTransformDsaSha1GetKlass() nogil + xmlSecTransformId xmlSecTransformEcdsaSha1GetKlass() nogil + xmlSecTransformId xmlSecTransformEcdsaSha224GetKlass() nogil + xmlSecTransformId xmlSecTransformEcdsaSha256GetKlass() nogil + xmlSecTransformId xmlSecTransformEcdsaSha384GetKlass() nogil + xmlSecTransformId xmlSecTransformEcdsaSha512GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacMd5GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacRipemd160GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacSha1GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacSha224GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacSha256GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacSha384GetKlass() nogil + xmlSecTransformId xmlSecTransformHmacSha512GetKlass() nogil + xmlSecTransformId xmlSecTransformMd5GetKlass() nogil + xmlSecTransformId xmlSecTransformRipemd160GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaMd5GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaRipemd160GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaSha1GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaSha224GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaSha256GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaSha384GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaSha512GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaPkcs1GetKlass() nogil + xmlSecTransformId xmlSecTransformRsaOaepGetKlass() nogil + xmlSecTransformId xmlSecTransformSha1GetKlass() nogil + xmlSecTransformId xmlSecTransformSha224GetKlass() nogil + xmlSecTransformId xmlSecTransformSha256GetKlass() nogil + xmlSecTransformId xmlSecTransformSha384GetKlass() nogil + xmlSecTransformId xmlSecTransformSha512GetKlass() nogil cdef class _Transform(object): diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index 55c876de..4218f64c 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -14,18 +14,18 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h ctypedef _xmlSecKeyDataKlass *xmlSecKeyDataId - xmlSecKeyDataId xmlSecKeyDataNameGetKlass() - xmlSecKeyDataId xmlSecKeyDataValueGetKlass() - xmlSecKeyDataId xmlSecKeyDataRetrievalMethodGetKlass() - xmlSecKeyDataId xmlSecKeyDataEncryptedKeyGetKlass() - xmlSecKeyDataId xmlSecKeyDataAesGetKlass() - xmlSecKeyDataId xmlSecKeyDataDesGetKlass() - xmlSecKeyDataId xmlSecKeyDataDsaGetKlass() - xmlSecKeyDataId xmlSecKeyDataEcdsaGetKlass() - xmlSecKeyDataId xmlSecKeyDataHmacGetKlass() - xmlSecKeyDataId xmlSecKeyDataRsaGetKlass() - xmlSecKeyDataId xmlSecKeyDataX509GetKlass() - xmlSecKeyDataId xmlSecKeyDataRawX509CertGetKlass() + xmlSecKeyDataId xmlSecKeyDataNameGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataValueGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataRetrievalMethodGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataEncryptedKeyGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataAesGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataDesGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataDsaGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataEcdsaGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataHmacGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataRsaGetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataX509GetKlass() nogil + xmlSecKeyDataId xmlSecKeyDataRawX509CertGetKlass() nogil ctypedef enum xmlSecKeyDataFormat: xmlSecKeyDataFormatUnknown = 0 diff --git a/src/xmlsec/tree.pxd b/src/xmlsec/tree.pxd index 5ed86d6e..1865fbe7 100644 --- a/src/xmlsec/tree.pxd +++ b/src/xmlsec/tree.pxd @@ -11,13 +11,13 @@ cdef extern from "xmlsec.h": # xmlsec/xmltree.h # xmlNode* xmlSecGetNextElementNode(xmlNode* node) xmlNode* xmlSecFindChild( - xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) + xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) nogil xmlNode* xmlSecFindParent( - xmlNode* node, const_xmlChar* name, const_xmlChar* ns) + xmlNode* node, const_xmlChar* name, const_xmlChar* ns) nogil xmlNode* xmlSecFindNode( - xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) + xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) nogil # xmlNode* xmlSecAddChild( # xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) diff --git a/tests/examples/test_decrypt.py b/tests/examples/test_decrypt.py index ba6e393e..f17f00f2 100644 --- a/tests/examples/test_decrypt.py +++ b/tests/examples/test_decrypt.py @@ -3,6 +3,7 @@ import xmlsec from .base import parse_xml, BASE_DIR, compare + def read_from_file(filename): with open(filename, "rb") as stream: return stream.read() diff --git a/tests/examples/test_encrypt.py b/tests/examples/test_encrypt.py index 31eb0894..d0fd0f9d 100644 --- a/tests/examples/test_encrypt.py +++ b/tests/examples/test_encrypt.py @@ -3,6 +3,7 @@ from .base import parse_xml, BASE_DIR from lxml import etree + def read_from_file(filename): with open(filename, "rb") as stream: return stream.read() @@ -32,7 +33,7 @@ def test_encrypt_xml(): # Encrypt! enc_ctx = xmlsec.EncryptionContext(manager) enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 128, xmlsec.KeyDataType.SESSION) - enc_data = enc_ctx.encrypt_xml(enc_data, data) + enc_datsa = enc_ctx.encrypt_xml(enc_data, data) assert enc_data is not None enc_method = xmlsec.tree.find_child(enc_data, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC) assert enc_method is not None From d4d23c7d4273fcecd680e1a31a6ff099ab02b57f Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 6 Nov 2015 11:07:18 +0300 Subject: [PATCH 016/378] Update travis.yaml: added package libxmlsec1-dev --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 237bae9f..1f17935d 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,6 +9,7 @@ addons: apt: packages: libxmlsec1 + libxmlsec1-dev libxmlsec1-openssl install: From 86e8b758be3b2e61758a2b0c7ff54e2dd873c8cc Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sat, 9 Jan 2016 19:40:14 +0300 Subject: [PATCH 017/378] Start using openssl implementation directly Since in most popular systems libxmlsec is built without support for loading crypto library dynamicly and cython does not support c-macroses this solution helps to fix work with native system library. --- setup.py | 2 +- src/xmlsec.h | 4 +-- src/xmlsec/constants.pxd | 74 ++++++++++++++++++++-------------------- src/xmlsec/constants.pyx | 74 ++++++++++++++++++++-------------------- src/xmlsec/key.pxd | 32 ++++++++--------- src/xmlsec/key.pyx | 51 ++++++++++++++++----------- src/xmlsec/utils.pxd | 10 +++--- src/xmlsec/utils.pyx | 8 ++--- 8 files changed, 134 insertions(+), 121 deletions(-) diff --git a/setup.py b/setup.py index 43c6074a..729fab5b 100644 --- a/setup.py +++ b/setup.py @@ -53,7 +53,7 @@ def make_extension(name, cython=True): for lib in ['libxml-2.0', 'xmlsec1-%s' % xmlsec_crypto]: config.update(parse(lib)) - config['extra_compile_args'] = ['-DXMLSEC_CRYPTO_OPENSSL=1'] + config['extra_compile_args'] = ['-DXMLSEC_CRYPTO_OPENSSL=1', '-DXMLSEC_NO_CRYPTO_DYNAMIC_LOADING=1'] # List-ify config for setuptools. for key in config: diff --git a/src/xmlsec.h b/src/xmlsec.h index e03abd21..0c0d9546 100644 --- a/src/xmlsec.h +++ b/src/xmlsec.h @@ -1,7 +1,7 @@ -#include -#include #include #include #include #include #include +#include +#include diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd index e1be9c75..ad8fed8b 100644 --- a/src/xmlsec/constants.pxd +++ b/src/xmlsec/constants.pxd @@ -76,43 +76,43 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NGetKlass() nogil xmlSecTransformId xmlSecTransformVisa3DHackGetKlass() nogil - xmlSecTransformId xmlSecTransformAes128CbcGetKlass() nogil - xmlSecTransformId xmlSecTransformAes192CbcGetKlass() nogil - xmlSecTransformId xmlSecTransformAes256CbcGetKlass() nogil - xmlSecTransformId xmlSecTransformKWAes128GetKlass() nogil - xmlSecTransformId xmlSecTransformKWAes192GetKlass() nogil - xmlSecTransformId xmlSecTransformKWAes256GetKlass() nogil - xmlSecTransformId xmlSecTransformDes3CbcGetKlass() nogil - xmlSecTransformId xmlSecTransformKWDes3GetKlass() nogil - xmlSecTransformId xmlSecTransformDsaSha1GetKlass() nogil - xmlSecTransformId xmlSecTransformEcdsaSha1GetKlass() nogil - xmlSecTransformId xmlSecTransformEcdsaSha224GetKlass() nogil - xmlSecTransformId xmlSecTransformEcdsaSha256GetKlass() nogil - xmlSecTransformId xmlSecTransformEcdsaSha384GetKlass() nogil - xmlSecTransformId xmlSecTransformEcdsaSha512GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacMd5GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacRipemd160GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacSha1GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacSha224GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacSha256GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacSha384GetKlass() nogil - xmlSecTransformId xmlSecTransformHmacSha512GetKlass() nogil - xmlSecTransformId xmlSecTransformMd5GetKlass() nogil - xmlSecTransformId xmlSecTransformRipemd160GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaMd5GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaRipemd160GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaSha1GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaSha224GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaSha256GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaSha384GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaSha512GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaPkcs1GetKlass() nogil - xmlSecTransformId xmlSecTransformRsaOaepGetKlass() nogil - xmlSecTransformId xmlSecTransformSha1GetKlass() nogil - xmlSecTransformId xmlSecTransformSha224GetKlass() nogil - xmlSecTransformId xmlSecTransformSha256GetKlass() nogil - xmlSecTransformId xmlSecTransformSha384GetKlass() nogil - xmlSecTransformId xmlSecTransformSha512GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformAes128CbcGetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformAes192CbcGetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformAes256CbcGetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformKWAes128GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformKWAes192GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformKWAes256GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformDes3CbcGetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformKWDes3GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformDsaSha1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha224GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha256GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha384GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha512GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacMd5GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacRipemd160GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacSha1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacSha224GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacSha256GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacSha384GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformHmacSha512GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformMd5GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRipemd160GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaMd5GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaRipemd160GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaSha1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaSha224GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaSha256GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaSha384GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaSha512GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaPkcs1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformRsaOaepGetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformSha1GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformSha224GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformSha256GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformSha384GetKlass() nogil + xmlSecTransformId xmlSecOpenSSLTransformSha512GetKlass() nogil cdef class _Transform(object): diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index 725b9d22..b99b713f 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -93,40 +93,40 @@ class Transform: REMOVE_XML_TAGS_C14N = _mkti(xmlSecTransformRemoveXmlTagsC14NGetKlass()) VISA3D_HACK = _mkti(xmlSecTransformVisa3DHackGetKlass()) - AES128 = _mkti(xmlSecTransformAes128CbcGetKlass()) - AES192 = _mkti(xmlSecTransformAes192CbcGetKlass()) - AES256 = _mkti(xmlSecTransformAes256CbcGetKlass()) - KW_AES128 = _mkti(xmlSecTransformKWAes128GetKlass()) - KW_AES192 = _mkti(xmlSecTransformKWAes192GetKlass()) - KW_AES256 = _mkti(xmlSecTransformKWAes256GetKlass()) - DES3 = _mkti(xmlSecTransformDes3CbcGetKlass()) - KW_DES3 = _mkti(xmlSecTransformKWDes3GetKlass()) - DSA_SHA1 = _mkti(xmlSecTransformDsaSha1GetKlass()) - ECDSA_SHA1 = _mkti(xmlSecTransformEcdsaSha1GetKlass()) - ECDSA_SHA224 = _mkti(xmlSecTransformEcdsaSha224GetKlass()) - ECDSA_SHA256 = _mkti(xmlSecTransformEcdsaSha256GetKlass()) - ECDSA_SHA384 = _mkti(xmlSecTransformEcdsaSha384GetKlass()) - ECDSA_SHA512 = _mkti(xmlSecTransformEcdsaSha512GetKlass()) - HMAC_MD5 = _mkti(xmlSecTransformHmacMd5GetKlass()) - HMAC_RIPEMD160 = _mkti(xmlSecTransformHmacRipemd160GetKlass()) - HMAC_SHA1 = _mkti(xmlSecTransformHmacSha1GetKlass()) - HMAC_SHA224 = _mkti(xmlSecTransformHmacSha224GetKlass()) - HMAC_SHA256 = _mkti(xmlSecTransformHmacSha256GetKlass()) - HMAC_SHA384 = _mkti(xmlSecTransformHmacSha384GetKlass()) - HMAC_SHA512 = _mkti(xmlSecTransformHmacSha512GetKlass()) - MD5 = _mkti(xmlSecTransformMd5GetKlass()) - RIPEMD160 = _mkti(xmlSecTransformRipemd160GetKlass()) - RSA_MD5 = _mkti(xmlSecTransformRsaMd5GetKlass()) - RSA_RIPEMD160 = _mkti(xmlSecTransformRsaRipemd160GetKlass()) - RSA_SHA1 = _mkti(xmlSecTransformRsaSha1GetKlass()) - RSA_SHA224 = _mkti(xmlSecTransformRsaSha224GetKlass()) - RSA_SHA256 = _mkti(xmlSecTransformRsaSha256GetKlass()) - RSA_SHA384 = _mkti(xmlSecTransformRsaSha384GetKlass()) - RSA_SHA512 = _mkti(xmlSecTransformRsaSha512GetKlass()) - RSA_PKCS1 = _mkti(xmlSecTransformRsaPkcs1GetKlass()) - RSA_OAEP = _mkti(xmlSecTransformRsaOaepGetKlass()) - SHA1 = _mkti(xmlSecTransformSha1GetKlass()) - SHA224 = _mkti(xmlSecTransformSha224GetKlass()) - SHA256 = _mkti(xmlSecTransformSha256GetKlass()) - SHA384 = _mkti(xmlSecTransformSha384GetKlass()) - SHA512 = _mkti(xmlSecTransformSha512GetKlass()) + AES128 = _mkti(xmlSecOpenSSLTransformAes128CbcGetKlass()) + AES192 = _mkti(xmlSecOpenSSLTransformAes192CbcGetKlass()) + AES256 = _mkti(xmlSecOpenSSLTransformAes256CbcGetKlass()) + KW_AES128 = _mkti(xmlSecOpenSSLTransformKWAes128GetKlass()) + KW_AES192 = _mkti(xmlSecOpenSSLTransformKWAes192GetKlass()) + KW_AES256 = _mkti(xmlSecOpenSSLTransformKWAes256GetKlass()) + DES3 = _mkti(xmlSecOpenSSLTransformDes3CbcGetKlass()) + KW_DES3 = _mkti(xmlSecOpenSSLTransformKWDes3GetKlass()) + DSA_SHA1 = _mkti(xmlSecOpenSSLTransformDsaSha1GetKlass()) + ECDSA_SHA1 = _mkti(xmlSecOpenSSLTransformEcdsaSha1GetKlass()) + ECDSA_SHA224 = _mkti(xmlSecOpenSSLTransformEcdsaSha224GetKlass()) + ECDSA_SHA256 = _mkti(xmlSecOpenSSLTransformEcdsaSha256GetKlass()) + ECDSA_SHA384 = _mkti(xmlSecOpenSSLTransformEcdsaSha384GetKlass()) + ECDSA_SHA512 = _mkti(xmlSecOpenSSLTransformEcdsaSha512GetKlass()) + HMAC_MD5 = _mkti(xmlSecOpenSSLTransformHmacMd5GetKlass()) + HMAC_RIPEMD160 = _mkti(xmlSecOpenSSLTransformHmacRipemd160GetKlass()) + HMAC_SHA1 = _mkti(xmlSecOpenSSLTransformHmacSha1GetKlass()) + HMAC_SHA224 = _mkti(xmlSecOpenSSLTransformHmacSha224GetKlass()) + HMAC_SHA256 = _mkti(xmlSecOpenSSLTransformHmacSha256GetKlass()) + HMAC_SHA384 = _mkti(xmlSecOpenSSLTransformHmacSha384GetKlass()) + HMAC_SHA512 = _mkti(xmlSecOpenSSLTransformHmacSha512GetKlass()) + MD5 = _mkti(xmlSecOpenSSLTransformMd5GetKlass()) + RIPEMD160 = _mkti(xmlSecOpenSSLTransformRipemd160GetKlass()) + RSA_MD5 = _mkti(xmlSecOpenSSLTransformRsaMd5GetKlass()) + RSA_RIPEMD160 = _mkti(xmlSecOpenSSLTransformRsaRipemd160GetKlass()) + RSA_SHA1 = _mkti(xmlSecOpenSSLTransformRsaSha1GetKlass()) + RSA_SHA224 = _mkti(xmlSecOpenSSLTransformRsaSha224GetKlass()) + RSA_SHA256 = _mkti(xmlSecOpenSSLTransformRsaSha256GetKlass()) + RSA_SHA384 = _mkti(xmlSecOpenSSLTransformRsaSha384GetKlass()) + RSA_SHA512 = _mkti(xmlSecOpenSSLTransformRsaSha512GetKlass()) + RSA_PKCS1 = _mkti(xmlSecOpenSSLTransformRsaPkcs1GetKlass()) + RSA_OAEP = _mkti(xmlSecOpenSSLTransformRsaOaepGetKlass()) + SHA1 = _mkti(xmlSecOpenSSLTransformSha1GetKlass()) + SHA224 = _mkti(xmlSecOpenSSLTransformSha224GetKlass()) + SHA256 = _mkti(xmlSecOpenSSLTransformSha256GetKlass()) + SHA384 = _mkti(xmlSecOpenSSLTransformSha384GetKlass()) + SHA512 = _mkti(xmlSecOpenSSLTransformSha512GetKlass()) diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index 4218f64c..37394907 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -18,14 +18,14 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h xmlSecKeyDataId xmlSecKeyDataValueGetKlass() nogil xmlSecKeyDataId xmlSecKeyDataRetrievalMethodGetKlass() nogil xmlSecKeyDataId xmlSecKeyDataEncryptedKeyGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataAesGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataDesGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataDsaGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataEcdsaGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataHmacGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataRsaGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataX509GetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataRawX509CertGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataAesGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataDesGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataDsaGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataEcdsaGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataHmacGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataRsaGetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataX509GetKlass() nogil + xmlSecKeyDataId xmlSecOpenSSLKeyDataRawX509CertGetKlass() nogil ctypedef enum xmlSecKeyDataFormat: xmlSecKeyDataFormatUnknown = 0 @@ -63,10 +63,10 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h xmlSecKeyPtr xmlSecKeyDuplicate(xmlSecKeyPtr) nogil - xmlSecKeyPtr xmlSecCryptoAppKeyLoad( + xmlSecKeyPtr xmlSecOpenSSLAppKeyLoad( const_char*, xmlSecKeyDataFormat, const_char*, void*, void *) nogil - xmlSecKeyPtr xmlSecCryptoAppKeyLoadMemory( + xmlSecKeyPtr xmlSecOpenSSLAppKeyLoadMemory( const_unsigned_char*, int, xmlSecKeyDataFormat, const_char*, void*, void*) nogil @@ -75,10 +75,10 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h # xmlSecKeyPtr xmlSecKeyReadMemory( # xmlSecKeyDataId, const_unsigned_char*, size_t) nogil - int xmlSecCryptoAppKeyCertLoad( + int xmlSecOpenSSLAppKeyCertLoad( xmlSecKeyPtr, const_char*, xmlSecKeyDataFormat) nogil - int xmlSecCryptoAppKeyCertLoadMemory( + int xmlSecOpenSSLAppKeyCertLoadMemory( xmlSecKeyPtr, const_unsigned_char*, int, xmlSecKeyDataFormat) nogil xmlSecKeyPtr xmlSecKeyGenerate( @@ -96,14 +96,14 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h void xmlSecKeysMngrDestroy(xmlSecKeysMngrPtr) nogil - int xmlSecCryptoAppDefaultKeysMngrInit(xmlSecKeysMngrPtr) nogil + int xmlSecOpenSSLAppDefaultKeysMngrInit(xmlSecKeysMngrPtr) nogil - int xmlSecCryptoAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr, xmlSecKeyPtr) nogil + int xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr, xmlSecKeyPtr) nogil - int xmlSecCryptoAppKeysMngrCertLoad( + int xmlSecOpenSSLAppKeysMngrCertLoad( xmlSecKeysMngrPtr, char * filename, xmlSecKeyDataFormat, xmlSecKeyDataType) nogil - int xmlSecCryptoAppKeysMngrCertLoadMemory( + int xmlSecOpenSSLAppKeysMngrCertLoadMemory( xmlSecKeysMngrPtr, const_unsigned_char *, size_t, xmlSecKeyDataFormat, xmlSecKeyDataType) nogil diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 8cf00107..c6d67b33 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -48,15 +48,14 @@ cdef class KeyData(object): VALUE = _mkkdi(xmlSecKeyDataValueGetKlass()) RETRIEVALMETHOD = _mkkdi(xmlSecKeyDataRetrievalMethodGetKlass()) ENCRYPTEDKEY = _mkkdi(xmlSecKeyDataEncryptedKeyGetKlass()) - AES = _mkkdi(xmlSecKeyDataAesGetKlass()) - DES = _mkkdi(xmlSecKeyDataDesGetKlass()) - DSA = _mkkdi(xmlSecKeyDataDsaGetKlass()) - ECDSA = _mkkdi(xmlSecKeyDataEcdsaGetKlass()) - HMAC = _mkkdi(xmlSecKeyDataHmacGetKlass()) - RSA = _mkkdi(xmlSecKeyDataRsaGetKlass()) - X509 = _mkkdi(xmlSecKeyDataX509GetKlass()) - RAWX509CERT = _mkkdi(xmlSecKeyDataRawX509CertGetKlass()) - + AES = _mkkdi(xmlSecOpenSSLKeyDataAesGetKlass()) + DES = _mkkdi(xmlSecOpenSSLKeyDataDesGetKlass()) + DSA = _mkkdi(xmlSecOpenSSLKeyDataDsaGetKlass()) + ECDSA = _mkkdi(xmlSecOpenSSLKeyDataEcdsaGetKlass()) + HMAC = _mkkdi(xmlSecOpenSSLKeyDataHmacGetKlass()) + RSA = _mkkdi(xmlSecOpenSSLKeyDataRsaGetKlass()) + X509 = _mkkdi(xmlSecOpenSSLKeyDataX509GetKlass()) + RAWX509CERT = _mkkdi(xmlSecOpenSSLKeyDataRawX509CertGetKlass()) cdef class KeyDataType(object): @@ -73,9 +72,14 @@ cdef class KeyDataType(object): cdef class Key(object): + def __init__(self): + self._handle = NULL + self._owner = True + def __dealloc__(self): if self._owner and self._handle != NULL: xmlSecKeyDestroy(self._handle) + self._handle = NULL def __deepcopy__(self): return self.__copy__() @@ -109,7 +113,7 @@ cdef class Key(object): c_data = data with nogil: - handle = xmlSecCryptoAppKeyLoadMemory( + handle = xmlSecOpenSSLAppKeyLoadMemory( c_data, c_size, format, c_password, NULL, NULL) if handle == NULL: @@ -131,7 +135,7 @@ cdef class Key(object): cdef Key instance with nogil: - handle = xmlSecCryptoAppKeyLoad( + handle = xmlSecOpenSSLAppKeyLoad( c_filename, format, c_password, NULL, NULL) if handle == NULL: @@ -195,7 +199,7 @@ cdef class Key(object): c_data = data with nogil: - rv = xmlSecCryptoAppKeyCertLoadMemory( + rv = xmlSecOpenSSLAppKeyCertLoadMemory( self._handle, c_data, c_size, format) if rv != 0: @@ -207,17 +211,23 @@ cdef class Key(object): cdef Key instance with nogil: - rv = xmlSecCryptoAppKeyCertLoad(self._handle, c_filename, format) + rv = xmlSecOpenSSLAppKeyCertLoad(self._handle, c_filename, format) if rv != 0: raise ValueError('Failed to load the certificate from the file.') property name: def __get__(self): - return _u(xmlSecKeyGetName(self._handle)) + if self._handle != NULL: + return _u(xmlSecKeyGetName(self._handle)) + else: + raise ValueError('Not ready.') def __set__(self, value): - xmlSecKeySetName(self._handle, _b(value)) + if self._handle != NULL: + xmlSecKeySetName(self._handle, _b(value)) + else: + raise ValueError('Not ready.') cdef class KeysManager(object): @@ -229,7 +239,7 @@ cdef class KeysManager(object): if handle == NULL: raise InternalError("failed to create keys manager", -1) - rv = xmlSecCryptoAppDefaultKeysMngrInit(handle) + rv = xmlSecOpenSSLAppDefaultKeysMngrInit(handle) if rv < 0: raise InternalError("failed to initialize keys manager", rv) self._handle = handle @@ -242,11 +252,14 @@ cdef class KeysManager(object): """add (a copy of) *key*.""" cdef int rv + if key._handle == NULL: + raise ValueError("invalid key") + cdef xmlSecKeyPtr key_handle = xmlSecKeyDuplicate(key._handle) if key_handle == NULL: raise InternalError("failed to copy key", -1) - rv = xmlSecCryptoAppDefaultKeysMngrAdoptKey(self._handle, key_handle) + rv = xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(self._handle, key_handle) if rv < 0: xmlSecKeyDestroy(key_handle) raise Error("failed to add key", rv) @@ -260,7 +273,7 @@ cdef class KeysManager(object): cdef const_char* c_filename = _b(filename) with nogil: - rv = xmlSecCryptoAppKeysMngrCertLoad(self._handle, c_filename, format, type) + rv = xmlSecOpenSSLAppKeysMngrCertLoad(self._handle, c_filename, format, type) if rv != 0: raise Error("failed to load certificate from '%s'" % filename, rv) @@ -280,7 +293,7 @@ cdef class KeysManager(object): c_data = data with nogil: - rv = xmlSecCryptoAppKeysMngrCertLoadMemory(self._handle, c_data, c_size, format, type) + rv = xmlSecOpenSSLAppKeysMngrCertLoadMemory(self._handle, c_data, c_size, format, type) if rv != 0: raise Error("failed to load certificate from memory", rv) diff --git a/src/xmlsec/utils.pxd b/src/xmlsec/utils.pxd index f5a2e878..86e828df 100644 --- a/src/xmlsec/utils.pxd +++ b/src/xmlsec/utils.pxd @@ -25,9 +25,9 @@ cdef extern from "xmlsec.h": # xmlsec/errors.h int xmlSecErrorsDefaultCallbackEnableOutput(int) nogil -cdef extern from "xmlsec.h": # xmlsec/app.h - int xmlSecCryptoInit() nogil - int xmlSecCryptoShutdown() nogil +cdef extern from "xmlsec.h": # xmlsec/openssl/app.h + int xmlSecOpenSSLInit() nogil + int xmlSecOpenSSLShutdown() nogil - int xmlSecCryptoAppInit(char* name) nogil - int xmlSecCryptoAppShutdown() nogil + int xmlSecOpenSSLAppInit(char* name) nogil + int xmlSecOpenSSLAppShutdown() nogil diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx index 8287bad1..3f5fc115 100644 --- a/src/xmlsec/utils.pyx +++ b/src/xmlsec/utils.pyx @@ -20,11 +20,11 @@ def init(): if r != 0: return False - r = xmlSecCryptoInit() + r = xmlSecOpenSSLInit() if r != 0: return False - r = xmlSecCryptoAppInit(NULL) + r = xmlSecOpenSSLAppInit(NULL) if r != 0: return False @@ -37,11 +37,11 @@ def shutdown(): This is called automatically upon interpreter termination and should not need to be called explicitly. """ - r = xmlSecCryptoAppShutdown() + r = xmlSecOpenSSLAppShutdown() if r != 0: return False - r = xmlSecCryptoShutdown() + r = xmlSecOpenSSLShutdown() if r != 0: return False From 8fb02d4bfba697c6a63dee73a51f0d09d0daa306 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sat, 9 Jan 2016 19:45:13 +0300 Subject: [PATCH 018/378] fixed typo in name of requires package --- .travis.yml | 1 + setup.cfg | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1f17935d..c807a90b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,6 +11,7 @@ addons: libxmlsec1 libxmlsec1-dev libxmlsec1-openssl + pkg-config install: - 'travis_retry pip install -e ".[test]" --use-mirrors' diff --git a/setup.cfg b/setup.cfg index 0a2ab086..87f9cdb9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [bdist_rpm] release = 1 -build-requires = pkgconfig xmlsec1-devel libxml2-devel xmlsec1-openssl-devel +build-requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel group = Development/Libraries -requires = xmlsec1 xmlsec1-openssl \ No newline at end of file +requires = xmlsec1 xmlsec1-openssl From 0ac221f144f8ad0b77b7c88dfb9908948fa7021e Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sat, 9 Jan 2016 22:55:48 +0300 Subject: [PATCH 019/378] Temporary disable ECDSA_* algorithms ECDSA_* support was added in version 1.2.19 --- src/xmlsec/constants.pxd | 10 +++++----- src/xmlsec/constants.pyx | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd index ad8fed8b..b7aedefd 100644 --- a/src/xmlsec/constants.pxd +++ b/src/xmlsec/constants.pxd @@ -85,11 +85,11 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h xmlSecTransformId xmlSecOpenSSLTransformDes3CbcGetKlass() nogil xmlSecTransformId xmlSecOpenSSLTransformKWDes3GetKlass() nogil xmlSecTransformId xmlSecOpenSSLTransformDsaSha1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha224GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha256GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha384GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha512GetKlass() nogil + # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha1GetKlass() nogil + # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha224GetKlass() nogil + # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha256GetKlass() nogil + # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha384GetKlass() nogil + # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha512GetKlass() nogil xmlSecTransformId xmlSecOpenSSLTransformHmacMd5GetKlass() nogil xmlSecTransformId xmlSecOpenSSLTransformHmacRipemd160GetKlass() nogil xmlSecTransformId xmlSecOpenSSLTransformHmacSha1GetKlass() nogil diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index b99b713f..6d2eecf5 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -102,11 +102,11 @@ class Transform: DES3 = _mkti(xmlSecOpenSSLTransformDes3CbcGetKlass()) KW_DES3 = _mkti(xmlSecOpenSSLTransformKWDes3GetKlass()) DSA_SHA1 = _mkti(xmlSecOpenSSLTransformDsaSha1GetKlass()) - ECDSA_SHA1 = _mkti(xmlSecOpenSSLTransformEcdsaSha1GetKlass()) - ECDSA_SHA224 = _mkti(xmlSecOpenSSLTransformEcdsaSha224GetKlass()) - ECDSA_SHA256 = _mkti(xmlSecOpenSSLTransformEcdsaSha256GetKlass()) - ECDSA_SHA384 = _mkti(xmlSecOpenSSLTransformEcdsaSha384GetKlass()) - ECDSA_SHA512 = _mkti(xmlSecOpenSSLTransformEcdsaSha512GetKlass()) + # ECDSA_SHA1 = _mkti(xmlSecOpenSSLTransformEcdsaSha1GetKlass()) + # ECDSA_SHA224 = _mkti(xmlSecOpenSSLTransformEcdsaSha224GetKlass()) + # ECDSA_SHA256 = _mkti(xmlSecOpenSSLTransformEcdsaSha256GetKlass()) + # ECDSA_SHA384 = _mkti(xmlSecOpenSSLTransformEcdsaSha384GetKlass()) + # ECDSA_SHA512 = _mkti(xmlSecOpenSSLTransformEcdsaSha512GetKlass()) HMAC_MD5 = _mkti(xmlSecOpenSSLTransformHmacMd5GetKlass()) HMAC_RIPEMD160 = _mkti(xmlSecOpenSSLTransformHmacRipemd160GetKlass()) HMAC_SHA1 = _mkti(xmlSecOpenSSLTransformHmacSha1GetKlass()) From ac4dde4c924aa64df6bae815e2d42867770e5a23 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sat, 9 Jan 2016 23:10:47 +0300 Subject: [PATCH 020/378] Disable ECDSA key support(temporary) --- src/xmlsec/key.pxd | 2 +- src/xmlsec/key.pyx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index 37394907..309bf891 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -21,7 +21,7 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h xmlSecKeyDataId xmlSecOpenSSLKeyDataAesGetKlass() nogil xmlSecKeyDataId xmlSecOpenSSLKeyDataDesGetKlass() nogil xmlSecKeyDataId xmlSecOpenSSLKeyDataDsaGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataEcdsaGetKlass() nogil + # xmlSecKeyDataId xmlSecOpenSSLKeyDataEcdsaGetKlass() nogil xmlSecKeyDataId xmlSecOpenSSLKeyDataHmacGetKlass() nogil xmlSecKeyDataId xmlSecOpenSSLKeyDataRsaGetKlass() nogil xmlSecKeyDataId xmlSecOpenSSLKeyDataX509GetKlass() nogil diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index c6d67b33..0621f6bb 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -51,7 +51,7 @@ cdef class KeyData(object): AES = _mkkdi(xmlSecOpenSSLKeyDataAesGetKlass()) DES = _mkkdi(xmlSecOpenSSLKeyDataDesGetKlass()) DSA = _mkkdi(xmlSecOpenSSLKeyDataDsaGetKlass()) - ECDSA = _mkkdi(xmlSecOpenSSLKeyDataEcdsaGetKlass()) + # ECDSA = _mkkdi(xmlSecOpenSSLKeyDataEcdsaGetKlass()) HMAC = _mkkdi(xmlSecOpenSSLKeyDataHmacGetKlass()) RSA = _mkkdi(xmlSecOpenSSLKeyDataRsaGetKlass()) X509 = _mkkdi(xmlSecOpenSSLKeyDataX509GetKlass()) From 7a858e4dd8300dd7d3514e06c59a80f3de7648b2 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 26 Jan 2016 12:07:32 -0800 Subject: [PATCH 021/378] Bump version --- src/xmlsec/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py index 32b168c9..6b91cfbc 100644 --- a/src/xmlsec/meta.py +++ b/src/xmlsec/meta.py @@ -1,2 +1,2 @@ -version = '0.3.3' +version = '0.4.0' description = 'Python bindings for the XML Security Library.' From 7e221f9eed61201a04a98e7303003469fb1e072c Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 26 Jan 2016 12:13:10 -0800 Subject: [PATCH 022/378] Bump version (again) --- src/xmlsec/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py index 6b91cfbc..6c223947 100644 --- a/src/xmlsec/meta.py +++ b/src/xmlsec/meta.py @@ -1,2 +1,2 @@ -version = '0.4.0' +version = '0.5.0' description = 'Python bindings for the XML Security Library.' From d05a65d516fbe00d0932ce21cdd7c0b3a0f44905 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 11 Feb 2016 16:24:46 +0300 Subject: [PATCH 023/378] Make KeyManager initilasiation lazy, depends on purpose of usage --- src/xmlsec/key.pxd | 3 ++ src/xmlsec/key.pyx | 25 +++++++++++--- src/xmlsec/utils.pyx | 2 +- tests/examples/base.py | 1 - tests/examples/sign4-doc.xml | 9 +++++ tests/examples/sign4-res.xml | 55 ++++++++++++++++++++++++++++++ tests/examples/test_sign.py | 64 +++++++++++++++++++++++++++++++++++ tests/examples/test_verify.py | 4 +-- 8 files changed, 155 insertions(+), 8 deletions(-) create mode 100644 tests/examples/sign4-doc.xml create mode 100644 tests/examples/sign4-res.xml diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index 309bf891..b8c39c37 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -98,6 +98,8 @@ cdef extern from "xmlsec.h": # xmlsec/keys.h int xmlSecOpenSSLAppDefaultKeysMngrInit(xmlSecKeysMngrPtr) nogil + int xmlSecOpenSSLKeysMngrInit(xmlSecKeysMngrPtr) nogil + int xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr, xmlSecKeyPtr) nogil int xmlSecOpenSSLAppKeysMngrCertLoad( @@ -118,3 +120,4 @@ cdef class Key(object): cdef class KeysManager(object): cdef xmlSecKeysMngrPtr _handle + cdef bint _mode diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 0621f6bb..12944b96 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -235,19 +235,33 @@ cdef class KeysManager(object): cdef int rv cdef xmlSecKeysMngrPtr handle + self._mode = 0 handle = xmlSecKeysMngrCreate() if handle == NULL: raise InternalError("failed to create keys manager", -1) - - rv = xmlSecOpenSSLAppDefaultKeysMngrInit(handle) - if rv < 0: - raise InternalError("failed to initialize keys manager", rv) self._handle = handle def __dealloc__(self): if self._handle != NULL: xmlSecKeysMngrDestroy(self._handle) + + def __ensure_init(self, expected_mode): + if self._mode == expected_mode: + return + + if self._mode != 0: + raise InternalError("Cannot use one manager for verify and sign", -1) + + if expected_mode == 1: + rv = xmlSecOpenSSLAppDefaultKeysMngrInit(self._handle) + else: + rv = xmlSecOpenSSLKeysMngrInit(self._handle) + + if rv < 0: + raise InternalError("failed to initialize keys manager", rv) + + def add_key(self, Key key): """add (a copy of) *key*.""" @@ -259,6 +273,7 @@ cdef class KeysManager(object): if key_handle == NULL: raise InternalError("failed to copy key", -1) + self.__ensure_init(1) rv = xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(self._handle, key_handle) if rv < 0: xmlSecKeyDestroy(key_handle) @@ -272,6 +287,7 @@ cdef class KeysManager(object): cdef int rv cdef const_char* c_filename = _b(filename) + self.__ensure_init(2) with nogil: rv = xmlSecOpenSSLAppKeysMngrCertLoad(self._handle, c_filename, format, type) @@ -292,6 +308,7 @@ cdef class KeysManager(object): c_size = len(data) c_data = data + self.__ensure_init(2) with nogil: rv = xmlSecOpenSSLAppKeysMngrCertLoadMemory(self._handle, c_data, c_size, format, type) diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx index 3f5fc115..3c4e8b8c 100644 --- a/src/xmlsec/utils.pyx +++ b/src/xmlsec/utils.pyx @@ -50,4 +50,4 @@ def shutdown(): def enable_debug_trace(flag): - xmlSecErrorsDefaultCallbackEnableOutput(flag) + xmlSecErrorsDefaultCallbackEnableOutput(1 if flag else 0) diff --git a/tests/examples/base.py b/tests/examples/base.py index 6415dbb4..b846f5b1 100644 --- a/tests/examples/base.py +++ b/tests/examples/base.py @@ -18,4 +18,3 @@ def compare(name, result): # Compare the results. assert expected_text == result_text - diff --git a/tests/examples/sign4-doc.xml b/tests/examples/sign4-doc.xml new file mode 100644 index 00000000..cc00479b --- /dev/null +++ b/tests/examples/sign4-doc.xml @@ -0,0 +1,9 @@ + + + + + Hello, World! + + diff --git a/tests/examples/sign4-res.xml b/tests/examples/sign4-res.xml new file mode 100644 index 00000000..a6fecb44 --- /dev/null +++ b/tests/examples/sign4-res.xml @@ -0,0 +1,55 @@ + + + Hello, World! + + + + + + + + + + + +ERS7F/ifxZoyTe0mhco+HeAEKGo= + + +G+mZNFqh9w0wIkDSbuYwvVDu7CMP8PEsw7jfwiZBC8nyF3loAtYKKAkdi6Zy3dJs +tU8qKfhzvabmCjdIrGkFTdtlCNCVKDMzwogFtxEX4Oh77X6jjx4b22XNJx4AbnUG +JV/EcsD+po8s5qVEXw62lRRd8cMDafbzOA/rBH96CMNgZhzxyaF9VRLa/vbt1ht2 +hE1KkdZCB4Y0Lv3QyeDL2jax3NFks9FUv8IqoWYQSvywdMLY2ZMiQ9UpPeVfMizi +trd5zDUSD/s3hyIEs4gD5NJF3HZPD/Fe2Zw1PBPj9eLADdEzcdueyCdPJ2YioFIi +1sMW/qPDhR/DoOJwGpUxwQ== + + +MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X +DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy +eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt +cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf +BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt +quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E +mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg +qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53 +7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w +Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG +A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp +ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw +MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA +MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY +1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn +ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL +NJ2D + + + \ No newline at end of file diff --git a/tests/examples/test_sign.py b/tests/examples/test_sign.py index c3041b32..309819f6 100644 --- a/tests/examples/test_sign.py +++ b/tests/examples/test_sign.py @@ -158,6 +158,70 @@ def test_sign_generated_template_pem_with_x509(): compare('sign3-res.xml', template) +def test_sign_generated_template_pem_with_x509_with_custom_ns(): + """ + Should sign a file using a dynamicaly created template, key from PEM + file and an X509 certificate with custom ns. + """ + + # Load document file. + template = parse_xml('sign4-doc.xml') + xmlsec.tree.add_ids(template, ["ID"]) + elem_id = template.get('ID', None) + if elem_id: + elem_id = '#' + elem_id + # Create a signature template for RSA-SHA1 enveloped signature. + signature_node = xmlsec.template.create( + template, + xmlsec.Transform.EXCL_C14N, + xmlsec.Transform.RSA_SHA1, ns='ds') + + assert signature_node is not None + + # Add the node to the document. + template.append(signature_node) + + # Add the node to the signature template. + ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1, uri=elem_id) + + # Add the enveloped transform descriptor. + xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) + # Add the excl_c14n transform descriptor. + xmlsec.template.add_transform(ref, xmlsec.Transform.EXCL_C14N) + + # Add the and nodes. + key_info = xmlsec.template.ensure_key_info(signature_node) + xmlsec.template.add_x509_data(key_info) + + # Create a digital signature context (no key manager is needed). + ctx = xmlsec.SignatureContext() + + # Load private key (assuming that there is no password). + filename = path.join(BASE_DIR, 'rsakey.pem') + key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) + + assert key is not None + + # Load the certificate and add it to the key. + filename = path.join(BASE_DIR, 'rsacert.pem') + key.load_cert_from_file(filename, xmlsec.KeyFormat.PEM) + + # Set key name to the file name (note: this is just a test). + key.name = path.basename(filename) + + # Set the key on the context. + ctx.key = key + + assert ctx.key is not None + assert ctx.key.name == path.basename(filename) + + # Sign the template. + ctx.sign(signature_node) + + # Assert the contents of the XML document against the expected result. + compare('sign4-res.xml', template) + + def test_sign_binary(): ctx = xmlsec.SignatureContext() filename = path.join(BASE_DIR, 'rsakey.pem') diff --git a/tests/examples/test_verify.py b/tests/examples/test_verify.py index 4d37fd7d..4e2381bb 100644 --- a/tests/examples/test_verify.py +++ b/tests/examples/test_verify.py @@ -4,14 +4,14 @@ from .base import parse_xml, BASE_DIR -@mark.parametrize('index', range(1, 4)) +@mark.parametrize('index', range(1, 5)) def test_verify_with_pem_file(index): """Should verify a signed file using a key from a PEM file. """ # Load the XML document. template = parse_xml('sign%d-res.xml' % index) - + xmlsec.tree.add_ids(template, ["ID"]) # Find the node. signature_node = xmlsec.tree.find_node(template, xmlsec.Node.SIGNATURE) From 762bff6b07fc7a6434fa4ef1bf10069d541b9e02 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 16 Feb 2016 01:29:18 +0300 Subject: [PATCH 024/378] Fixed memory corruption in _KeyData --- src/xmlsec.h | 8 +++++--- src/xmlsec/key.pyx | 25 +++++-------------------- src/xmlsec/utils.pyx | 24 ++++++++++++------------ 3 files changed, 22 insertions(+), 35 deletions(-) diff --git a/src/xmlsec.h b/src/xmlsec.h index 0c0d9546..ac0f3e75 100644 --- a/src/xmlsec.h +++ b/src/xmlsec.h @@ -1,7 +1,9 @@ -#include +#include +#include +#include #include #include -#include -#include +#include #include #include +#include diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 12944b96..31bf5728 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -239,29 +239,17 @@ cdef class KeysManager(object): handle = xmlSecKeysMngrCreate() if handle == NULL: raise InternalError("failed to create keys manager", -1) + rv = xmlSecOpenSSLAppDefaultKeysMngrInit(handle) + if rv < 0: + xmlSecKeysMngrDestroy(handle) + raise InternalError("failed to init manager", rv) + self._handle = handle def __dealloc__(self): if self._handle != NULL: xmlSecKeysMngrDestroy(self._handle) - - def __ensure_init(self, expected_mode): - if self._mode == expected_mode: - return - - if self._mode != 0: - raise InternalError("Cannot use one manager for verify and sign", -1) - - if expected_mode == 1: - rv = xmlSecOpenSSLAppDefaultKeysMngrInit(self._handle) - else: - rv = xmlSecOpenSSLKeysMngrInit(self._handle) - - if rv < 0: - raise InternalError("failed to initialize keys manager", rv) - - def add_key(self, Key key): """add (a copy of) *key*.""" @@ -273,7 +261,6 @@ cdef class KeysManager(object): if key_handle == NULL: raise InternalError("failed to copy key", -1) - self.__ensure_init(1) rv = xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(self._handle, key_handle) if rv < 0: xmlSecKeyDestroy(key_handle) @@ -287,7 +274,6 @@ cdef class KeysManager(object): cdef int rv cdef const_char* c_filename = _b(filename) - self.__ensure_init(2) with nogil: rv = xmlSecOpenSSLAppKeysMngrCertLoad(self._handle, c_filename, format, type) @@ -308,7 +294,6 @@ cdef class KeysManager(object): c_size = len(data) c_data = data - self.__ensure_init(2) with nogil: rv = xmlSecOpenSSLAppKeysMngrCertLoadMemory(self._handle, c_data, c_size, format, type) diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx index 3c4e8b8c..94e7fd26 100644 --- a/src/xmlsec/utils.pyx +++ b/src/xmlsec/utils.pyx @@ -16,16 +16,16 @@ def init(): This is called upon library import and does not need to be called again (unless @ref _shutdown is called explicitly). """ - r = xmlSecInit() - if r != 0: + if xmlSecInit() < 0: return False - r = xmlSecOpenSSLInit() - if r != 0: + if xmlSecOpenSSLAppInit(NULL) < 0: + xmlSecShutdown() return False - r = xmlSecOpenSSLAppInit(NULL) - if r != 0: + if xmlSecOpenSSLInit() < 0: + xmlSecOpenSSLAppShutdown() + xmlSecShutdown() return False return True @@ -37,16 +37,16 @@ def shutdown(): This is called automatically upon interpreter termination and should not need to be called explicitly. """ - r = xmlSecOpenSSLAppShutdown() - if r != 0: + if xmlSecOpenSSLShutdown() < 0: return False - r = xmlSecOpenSSLShutdown() - if r != 0: + if xmlSecOpenSSLAppShutdown() < 0: return False - r = xmlSecShutdown() - return r == 0 + if xmlSecShutdown() < 0: + return False + + return True def enable_debug_trace(flag): From a66c75cbaa200851f1895d0b98ad906f9f7a3560 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 16 Feb 2016 01:40:03 +0300 Subject: [PATCH 025/378] Removed unused variable _mode --- src/xmlsec/key.pxd | 1 - src/xmlsec/key.pyx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd index b8c39c37..ac188da4 100644 --- a/src/xmlsec/key.pxd +++ b/src/xmlsec/key.pxd @@ -120,4 +120,3 @@ cdef class Key(object): cdef class KeysManager(object): cdef xmlSecKeysMngrPtr _handle - cdef bint _mode diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index 31bf5728..fb9e6da4 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -235,7 +235,6 @@ cdef class KeysManager(object): cdef int rv cdef xmlSecKeysMngrPtr handle - self._mode = 0 handle = xmlSecKeysMngrCreate() if handle == NULL: raise InternalError("failed to create keys manager", -1) From e373d2b763b5f92223bad57782374c9e71788d26 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Wed, 13 Apr 2016 21:07:50 -0700 Subject: [PATCH 026/378] Prepare version 0.6.0 --- src/xmlsec/meta.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py index 6c223947..9ea72b40 100644 --- a/src/xmlsec/meta.py +++ b/src/xmlsec/meta.py @@ -1,2 +1,2 @@ -version = '0.5.0' +version = '0.6.0' description = 'Python bindings for the XML Security Library.' From 466b991f6f7dcf9ced3bf58c0ef4a56de4479f89 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 24 May 2016 11:27:45 +0300 Subject: [PATCH 027/378] The constant 'xmlSecXkmsNs' was removed The xkms support was removed from libxmlsec1 Fixed issue #26 --- src/xmlsec/constants.pxd | 1 - src/xmlsec/constants.pyx | 1 - 2 files changed, 2 deletions(-) diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd index b7aedefd..40a3d2b8 100644 --- a/src/xmlsec/constants.pxd +++ b/src/xmlsec/constants.pxd @@ -6,7 +6,6 @@ cdef extern from "xmlsec.h": # xmlsec/strings.h const_xmlChar* xmlSecNs const_xmlChar* xmlSecDSigNs const_xmlChar* xmlSecEncNs - const_xmlChar* xmlSecXkmsNs const_xmlChar* xmlSecXPathNs const_xmlChar* xmlSecXPath2Ns const_xmlChar* xmlSecXPointerNs diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx index 6d2eecf5..a6de7cd8 100644 --- a/src/xmlsec/constants.pyx +++ b/src/xmlsec/constants.pyx @@ -17,7 +17,6 @@ class Namespace: BASE = _u(xmlSecNs) DS = _u(xmlSecDSigNs) ENC = _u(xmlSecEncNs) - XKMS = _u(xmlSecXkmsNs) XPATH = _u(xmlSecXPathNs) XPATH2 = _u(xmlSecXPath2Ns) XPOINTER = _u(xmlSecXPointerNs) From 11e15c64eb656b3714bb9668c2be5a69cd194310 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Sun, 5 Jun 2016 17:56:41 -0300 Subject: [PATCH 028/378] Added missing function to include X509 data to KeyInfo --- src/xmlsec/template.pxd | 14 ++++++++ src/xmlsec/template.pyx | 65 ++++++++++++++++++++++++++++++++++ tests/examples/base.py | 3 ++ tests/examples/sign5-doc.xml | 9 +++++ tests/examples/sign5-res.xml | 67 ++++++++++++++++++++++++++++++++++++ tests/examples/test_sign.py | 65 ++++++++++++++++++++++++++++++++++ 6 files changed, 223 insertions(+) create mode 100644 tests/examples/sign5-doc.xml create mode 100644 tests/examples/sign5-res.xml diff --git a/src/xmlsec/template.pxd b/src/xmlsec/template.pxd index cdc3b183..e7510f2e 100644 --- a/src/xmlsec/template.pxd +++ b/src/xmlsec/template.pxd @@ -24,6 +24,20 @@ cdef extern from "xmlsec.h": # xmlsec/templates.h xmlNode* xmlSecTmplKeyInfoAddX509Data(xmlNode* node) nogil + xmlNode* xmlSecTmplX509DataAddIssuerSerial(xmlNode* node) nogil + + xmlNode* xmlSecTmplX509IssuerSerialAddIssuerName(xmlNode* node, const_xmlChar* name) nogil + + xmlNode* xmlSecTmplX509IssuerSerialAddSerialNumber(xmlNode* node, const_xmlChar* serial) nogil + + xmlNode* xmlSecTmplX509DataAddSubjectName(xmlNode* node) nogil + + xmlNode* xmlSecTmplX509DataAddSKI (xmlNode* node) nogil + + xmlNode* xmlSecTmplX509DataAddCertificate (xmlNode* node) nogil + + xmlNode* xmlSecTmplX509DataAddCRL (xmlNode* node) nogil + xmlNode* xmlSecTmplKeyInfoAddEncryptedKey( xmlNode* keyInfoNode, xmlSecTransformId encMethodId, const_xmlChar *id, const_xmlChar *type, const_xmlChar *recipient) nogil diff --git a/src/xmlsec/template.pyx b/src/xmlsec/template.pyx index 37892196..d63bf2dd 100644 --- a/src/xmlsec/template.pyx +++ b/src/xmlsec/template.pyx @@ -89,6 +89,71 @@ def add_x509_data(_Element node not None): return elementFactory(node._doc, c_node) +def x509_data_add_issuer_serial(_Element node not None): + + cdef xmlNode* c_node + + c_node = xmlSecTmplX509DataAddIssuerSerial(node._c_node) + + return elementFactory(node._doc, c_node) + + +def x509_issuer_serial_add_issuer_name(_Element node not None, name=None): + + cdef xmlNode* c_node + cdef const_xmlChar* c_name = _b(name) + + c_node = xmlSecTmplX509IssuerSerialAddIssuerName(node._c_node, c_name) + + return elementFactory(node._doc, c_node) + + +def x509_issuer_serial_add_serial_number(_Element node not None, serial=None): + + cdef xmlNode* c_node + cdef const_xmlChar* c_serial = _b(serial) + + c_node = xmlSecTmplX509IssuerSerialAddSerialNumber(node._c_node, c_serial) + + return elementFactory(node._doc, c_node) + + +def x509_data_add_subject_name(_Element node not None): + + cdef xmlNode* c_node + + c_node = xmlSecTmplX509DataAddSubjectName(node._c_node) + + return elementFactory(node._doc, c_node) + + +def x509_data_add_ski(_Element node not None): + + cdef xmlNode* c_node + + c_node = xmlSecTmplX509DataAddSKI(node._c_node) + + return elementFactory(node._doc, c_node) + + +def x509_data_add_certificate(_Element node not None): + + cdef xmlNode* c_node + + c_node = xmlSecTmplX509DataAddCertificate(node._c_node) + + return elementFactory(node._doc, c_node) + + +def x509_data_add_crl(_Element node not None): + + cdef xmlNode* c_node + + c_node = xmlSecTmplX509DataAddCRL(node._c_node) + + return elementFactory(node._doc, c_node) + + def add_encrypted_key(_Element node not None, _Transform method not None, id=None, diff --git a/tests/examples/base.py b/tests/examples/base.py index b846f5b1..fadee59b 100644 --- a/tests/examples/base.py +++ b/tests/examples/base.py @@ -17,4 +17,7 @@ def compare(name, result): result_text = etree.tostring(result, pretty_print=False) # Compare the results. + if expected_text != result_text: + print(expected_text) + print(result_text) assert expected_text == result_text diff --git a/tests/examples/sign5-doc.xml b/tests/examples/sign5-doc.xml new file mode 100644 index 00000000..7676fffe --- /dev/null +++ b/tests/examples/sign5-doc.xml @@ -0,0 +1,9 @@ + + + + + Hello, World! + + diff --git a/tests/examples/sign5-res.xml b/tests/examples/sign5-res.xml new file mode 100644 index 00000000..4d8d28be --- /dev/null +++ b/tests/examples/sign5-res.xml @@ -0,0 +1,67 @@ + + + + + Hello, World! + + + + + + + + + + +HjY8ilZAIEM2tBbPn5mYO1ieIX4= + + +SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i +D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP +XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN +T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4 +JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r +3k1ACVX9f8aHfQQdJOmLFQ== + + + + + + +Test Issuer +1 + +MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X +DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy +eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt +cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf +BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt +quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E +mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg +qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53 +7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w +Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG +A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp +ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw +MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA +MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY +1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn +ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL +NJ2D +emailAddress=xmlsec@aleksey.com,CN=Aleksey Sanin,OU=Examples RSA Certificate,O=XML Security Library (http://www.aleksey.com/xmlsec),ST=California,C=US +JIQs8tRZIGKLLlyGkKOqMLonGpw= + + + diff --git a/tests/examples/test_sign.py b/tests/examples/test_sign.py index 309819f6..d873ba8c 100644 --- a/tests/examples/test_sign.py +++ b/tests/examples/test_sign.py @@ -222,6 +222,71 @@ def test_sign_generated_template_pem_with_x509_with_custom_ns(): compare('sign4-res.xml', template) +def test_sign_generated_template_pem_with_x509_with_cert_info(): + """ + Should sign a file using a dynamicaly created template, key from PEM + file and an X509 certificate. + """ + + # Load document file. + template = parse_xml('sign5-doc.xml') + + # Create a signature template for RSA-SHA1 enveloped signature. + signature_node = xmlsec.template.create( + template, + xmlsec.Transform.EXCL_C14N, + xmlsec.Transform.RSA_SHA1) + + assert signature_node is not None + + # Add the node to the document. + template.append(signature_node) + + # Add the node to the signature template. + ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) + + # Add the enveloped transform descriptor. + xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) + + # Add the and nodes. + key_info = xmlsec.template.ensure_key_info(signature_node) + x509_data = xmlsec.template.add_x509_data(key_info) + xmlsec.template.x509_data_add_subject_name(x509_data) + xmlsec.template.x509_data_add_certificate(x509_data) + xmlsec.template.x509_data_add_ski(x509_data) + x509_issuer_serial = xmlsec.template.x509_data_add_issuer_serial(x509_data) + xmlsec.template.x509_issuer_serial_add_issuer_name(x509_issuer_serial, 'Test Issuer') + xmlsec.template.x509_issuer_serial_add_serial_number(x509_issuer_serial, '1') + + # Create a digital signature context (no key manager is needed). + ctx = xmlsec.SignatureContext() + + # Load private key (assuming that there is no password). + filename = path.join(BASE_DIR, 'rsakey.pem') + key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) + + assert key is not None + + # Load the certificate and add it to the key. + filename = path.join(BASE_DIR, 'rsacert.pem') + key.load_cert_from_file(filename, xmlsec.KeyFormat.PEM) + + # Set key name to the file name (note: this is just a test). + key.name = path.basename(filename) + + # Set the key on the context. + ctx.key = key + + assert ctx.key is not None + assert ctx.key.name == path.basename(filename) + + # Sign the template. + ctx.sign(signature_node) + + # Assert the contents of the XML document against the expected result. + compare('sign5-res.xml', template) + + def test_sign_binary(): ctx = xmlsec.SignatureContext() filename = path.join(BASE_DIR, 'rsakey.pem') From e349ec8f8db4b93181eb500fe109d7f24e53d968 Mon Sep 17 00:00:00 2001 From: Sergio Garcia Date: Sun, 5 Jun 2016 23:55:44 -0300 Subject: [PATCH 029/378] Remove dummy debug message and fixed formatting --- src/xmlsec/template.pxd | 6 +++--- tests/examples/base.py | 3 --- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/xmlsec/template.pxd b/src/xmlsec/template.pxd index e7510f2e..4994e8be 100644 --- a/src/xmlsec/template.pxd +++ b/src/xmlsec/template.pxd @@ -32,11 +32,11 @@ cdef extern from "xmlsec.h": # xmlsec/templates.h xmlNode* xmlSecTmplX509DataAddSubjectName(xmlNode* node) nogil - xmlNode* xmlSecTmplX509DataAddSKI (xmlNode* node) nogil + xmlNode* xmlSecTmplX509DataAddSKI(xmlNode* node) nogil - xmlNode* xmlSecTmplX509DataAddCertificate (xmlNode* node) nogil + xmlNode* xmlSecTmplX509DataAddCertificate(xmlNode* node) nogil - xmlNode* xmlSecTmplX509DataAddCRL (xmlNode* node) nogil + xmlNode* xmlSecTmplX509DataAddCRL(xmlNode* node) nogil xmlNode* xmlSecTmplKeyInfoAddEncryptedKey( xmlNode* keyInfoNode, xmlSecTransformId encMethodId, diff --git a/tests/examples/base.py b/tests/examples/base.py index fadee59b..b846f5b1 100644 --- a/tests/examples/base.py +++ b/tests/examples/base.py @@ -17,7 +17,4 @@ def compare(name, result): result_text = etree.tostring(result, pretty_print=False) # Compare the results. - if expected_text != result_text: - print(expected_text) - print(result_text) assert expected_text == result_text From d7feedf241b5fc034cff1f1b46248bb9ed0cef55 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 5 Jul 2016 23:10:51 -0700 Subject: [PATCH 030/378] Clear the error stack when needed. --- src/xmlsec/key.pyx | 23 +++++++++++++++++++++-- src/xmlsec/ssl.pxd | 4 ++++ 2 files changed, 25 insertions(+), 2 deletions(-) create mode 100644 src/xmlsec/ssl.pxd diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx index fb9e6da4..f19c2ae7 100644 --- a/src/xmlsec/key.pyx +++ b/src/xmlsec/key.pyx @@ -5,6 +5,7 @@ from .key cimport * from .utils cimport _b, _u from .error import * from copy import copy +from .ssl cimport ERR_clear_error __all__ = [ 'KeyData', @@ -117,6 +118,9 @@ cdef class Key(object): c_data, c_size, format, c_password, NULL, NULL) if handle == NULL: + # Clear the error stack generated from openssl + ERR_clear_error() + raise ValueError("failed to load key") # Construct and return a new instance. @@ -139,6 +143,9 @@ cdef class Key(object): c_filename, format, c_password, NULL, NULL) if handle == NULL: + # Clear the error stack generated from openssl + ERR_clear_error() + raise ValueError("failed to load key from '%s'" % filename) # Construct and return a new instance. @@ -159,7 +166,10 @@ cdef class Key(object): handle = xmlSecKeyGenerate(data_id, size, type) if handle == NULL: - raise ValueError("failed to generate key") + # Clear the error stack generated from openssl + ERR_clear_error() + + raise ValueError("failed to generate key") # Construct and return a new instance. instance = cls() @@ -180,7 +190,10 @@ cdef class Key(object): handle = xmlSecKeyReadBinaryFile(data_id, c_filename) if handle == NULL: - raise ValueError("failed to load from '%s'" % filename) + # Clear the error stack generated from openssl + ERR_clear_error() + + raise ValueError("failed to load from '%s'" % filename) # Construct and return a new instance. instance = cls() @@ -203,6 +216,9 @@ cdef class Key(object): self._handle, c_data, c_size, format) if rv != 0: + # Clear the error stack generated from openssl + ERR_clear_error() + raise ValueError('Failed to load the certificate from the I/O stream.') def load_cert_from_file(self, filename, xmlSecKeyDataFormat format): @@ -214,6 +230,9 @@ cdef class Key(object): rv = xmlSecOpenSSLAppKeyCertLoad(self._handle, c_filename, format) if rv != 0: + # Clear the error stack generated from openssl + ERR_clear_error() + raise ValueError('Failed to load the certificate from the file.') property name: diff --git a/src/xmlsec/ssl.pxd b/src/xmlsec/ssl.pxd new file mode 100644 index 00000000..90b2fd09 --- /dev/null +++ b/src/xmlsec/ssl.pxd @@ -0,0 +1,4 @@ + + +cdef extern from "xmlsec.h": + void ERR_clear_error() nogil From db5cb6a667ad9efc76971d8d03a7ca261a101176 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sun, 22 Jan 2017 19:43:12 +0300 Subject: [PATCH 031/378] Rewrote whole module on pure C --- .gitignore | 1 - .travis.yml | 9 +- MANIFEST.in | 3 +- README.md | 16 +- requirements-test.txt | 2 + requirements.txt | 2 + setup.py | 142 +++---- src/common.h | 30 ++ src/constants.c | 516 +++++++++++++++++++++++ src/constants.h | 31 ++ src/debug.h | 23 + src/ds.c | 561 +++++++++++++++++++++++++ src/enc.c | 452 ++++++++++++++++++++ src/exception.c | 166 ++++++++ src/exception.h | 25 ++ src/keys.c | 695 +++++++++++++++++++++++++++++++ src/keys.h | 37 ++ src/lxml.c | 38 ++ src/lxml.h | 31 ++ src/main.c | 245 +++++++++++ src/platform.h | 80 ++++ src/template.c | 738 +++++++++++++++++++++++++++++++++ src/tree.c | 228 ++++++++++ src/utils.c | 49 +++ src/utils.h | 22 + src/xmlsec.h | 9 - src/xmlsec/__init__.py | 18 - src/xmlsec/constants.pxd | 118 ------ src/xmlsec/constants.pyx | 131 ------ src/xmlsec/ds.pxd | 125 ------ src/xmlsec/ds.pyx | 198 --------- src/xmlsec/enc.pxd | 57 --- src/xmlsec/enc.pyx | 230 ---------- src/xmlsec/error.py | 15 - src/xmlsec/key.pxd | 122 ------ src/xmlsec/key.pyx | 319 -------------- src/xmlsec/meta.py | 2 - src/xmlsec/ssl.pxd | 4 - src/xmlsec/template.pxd | 51 --- src/xmlsec/template.pyx | 217 ---------- src/xmlsec/tree.pxd | 68 --- src/xmlsec/tree.pyx | 84 ---- src/xmlsec/utils.pxd | 33 -- src/xmlsec/utils.pyx | 53 --- tests/examples/test_decrypt.py | 2 +- tests/examples/test_verify.py | 23 + 46 files changed, 4066 insertions(+), 1955 deletions(-) create mode 100644 requirements-test.txt create mode 100644 requirements.txt create mode 100644 src/common.h create mode 100644 src/constants.c create mode 100644 src/constants.h create mode 100644 src/debug.h create mode 100644 src/ds.c create mode 100644 src/enc.c create mode 100644 src/exception.c create mode 100644 src/exception.h create mode 100644 src/keys.c create mode 100644 src/keys.h create mode 100644 src/lxml.c create mode 100644 src/lxml.h create mode 100644 src/main.c create mode 100644 src/platform.h create mode 100644 src/template.c create mode 100644 src/tree.c create mode 100644 src/utils.c create mode 100644 src/utils.h delete mode 100644 src/xmlsec.h delete mode 100644 src/xmlsec/__init__.py delete mode 100644 src/xmlsec/constants.pxd delete mode 100644 src/xmlsec/constants.pyx delete mode 100644 src/xmlsec/ds.pxd delete mode 100644 src/xmlsec/ds.pyx delete mode 100644 src/xmlsec/enc.pxd delete mode 100644 src/xmlsec/enc.pyx delete mode 100644 src/xmlsec/error.py delete mode 100644 src/xmlsec/key.pxd delete mode 100644 src/xmlsec/key.pyx delete mode 100644 src/xmlsec/meta.py delete mode 100644 src/xmlsec/ssl.pxd delete mode 100644 src/xmlsec/template.pxd delete mode 100644 src/xmlsec/template.pyx delete mode 100644 src/xmlsec/tree.pxd delete mode 100644 src/xmlsec/tree.pyx delete mode 100644 src/xmlsec/utils.pxd delete mode 100644 src/xmlsec/utils.pyx diff --git a/.gitignore b/.gitignore index 27f72d21..f39e8aba 100644 --- a/.gitignore +++ b/.gitignore @@ -11,4 +11,3 @@ *.pyo *.egg* *.so -*.c diff --git a/.travis.yml b/.travis.yml index 33b8acd1..f0649bd5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,10 @@ +dist: trusty sudo: false language: python python: - '2.7' - - '3.3' - '3.4' + - '3.5' addons: apt: @@ -16,6 +17,8 @@ addons: - pkg-config install: - - travis_retry pip install -e ".[test]" + - travis_retry pip install -r requirements-test.txt + - travis_retry pip install -e "." + - pip list -script: py.test +script: 'py.test tests' diff --git a/MANIFEST.in b/MANIFEST.in index 941c90f1..a9042a51 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,2 +1 @@ -include src/*.h -include src/xmlsec/*.pxd +include src/* diff --git a/README.md b/README.md index 965b8aa6..17d66502 100644 --- a/README.md +++ b/README.md @@ -15,9 +15,9 @@ Check the [examples](https://github.com/mehcode/python-xmlsec/tree/master/tests/ #### Linux (Debian) ```sh - apt-get install libxml2-dev libxmlsec1-dev + apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-opensssl ``` - + #### Linux (CentOS) ```sh @@ -86,7 +86,8 @@ include the appropriate files from the libxml2 and libxmlsec1 libraries. This will download all dependencies required for running the unit tests. ```sh - pip install -e ".[test]" + pip install -r requirements-test.txt + pip install -e "." ``` ### Running the test suite @@ -96,9 +97,16 @@ include the appropriate files from the libxml2 and libxmlsec1 libraries. 2. Run the unit tests. ```sh - py.test + py.test tests ``` +## Versions of python +The following versions of python is supported + - python2.7 + - python3.4 + - python3.5 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + - python3.6 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + ## License Unless otherwise noted, all files contained within this project are liensed under the MIT opensource license. See the included file LICENSE or visit [opensource.org][] for more information. diff --git a/requirements-test.txt b/requirements-test.txt new file mode 100644 index 00000000..26b77f68 --- /dev/null +++ b/requirements-test.txt @@ -0,0 +1,2 @@ +-r requirements.txt +pytest diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 00000000..cd185c22 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,2 @@ +pkgconfig +lxml >= 3.0 diff --git a/setup.py b/setup.py index 93b2a87f..2837cbae 100644 --- a/setup.py +++ b/setup.py @@ -1,125 +1,87 @@ -#! /usr/bin/env python -# -*- coding: utf-8 -*- -# from __future__ import absolute_import, unicode_literals, division -from os import path -from pkgutil import get_importer -from setuptools import setup, Extension -from functools import wraps +from __future__ import print_function +import glob +import os +import pkgconfig +from setuptools import setup +from setuptools import Extension +import sys -def lazy(function): +import lxml - @wraps(function) - def wrapped(*args, **kwargs): +__name__ = "xmlsec" +__version__ = "1.0.1" +__description__ = "Python bindings for the XML Security Library" - class LazyProxy(Extension): - __arguments = dict() - def __init__(self, function, args, kwargs): - self.__arguments["function"] = function - self.__arguments["args"] = args - self.__arguments["kwargs"] = kwargs - self.__arguments["result"] = None +def is_debug(): + return bool(os.getenv("PYXMLSEC_DEBUG")) - def __getattr__(self, item): - if self.__arguments["result"] is None: - self.__arguments["result"] = self.__arguments["function"](*self.__arguments["args"], - **self.__arguments["kwargs"]) - return getattr(self.__arguments["result"], item) +macroses = [("MODULE_NAME", __name__), ("MODULE_VERSION", __version__), ("MODULE_DOC", __description__)] +cflags = ["-g", "-std=c99", "-fno-strict-aliasing", "-Wno-error=declaration-after-statement", "-Werror=implicit-function-declaration"] - def __setattr__(self, name, value): - if self.__arguments["result"] is None: - self.__arguments["result"] = self.__arguments["function"](*self.__arguments["args"], - **self.__arguments["kwargs"]) - setattr(self.__arguments["result"], name, value) +if is_debug(): + macroses.append(("PYXMLSEC_ENABLE_DEBUG", 1)) + cflags.extend(["-Wall", "-O0"]) +else: + cflags.extend(["-Os"]) - return LazyProxy(function, args, kwargs) - return wrapped +config = pkgconfig.parse("xmlsec1") -@lazy -def make_extension(name, cython=True): - from pkgconfig import parse +def add_to_config(key, args): + value = list(config.get(key, [])) + value.extend(args) + config[key] = value - # Declare the crypto implementation. - xmlsec_crypto = 'openssl' - # Process the `pkg-config` utility and discover include and library - # directories. - config = {} - for lib in ['libxml-2.0', 'xmlsec1-%s' % xmlsec_crypto]: - config.update(parse(lib)) +add_to_config('define_macros', macroses) +add_to_config('include_dirs', lxml.get_include()) - config['extra_compile_args'] = ['-DXMLSEC_CRYPTO_OPENSSL=1', '-DXMLSEC_NO_CRYPTO_DYNAMIC_LOADING=1'] +print(config, file=sys.stderr) - # List-ify config for setuptools. - for key in config: - config[key] = list(config[key]) - if 'include_dirs' not in config: - config['include_dirs'] = [] +def find_sources(path): + return glob.glob(os.path.join(path, "*.c")) - # Add the source directories for inclusion. - import lxml - config['include_dirs'].insert(0, path.dirname(lxml.__file__)) - config['include_dirs'].insert(0, path.join(path.dirname(lxml.__file__), 'includes')) - config['include_dirs'].insert(0, 'src') - - # Resolve extension location from name. - location = path.join('src', *name.split('.')) - location += '.pyx' if cython else '.c' - - # Create and return the extension. - return Extension(name, [location], **config) - - -# Navigate, import, and retrieve the metadata of the project. -meta = get_importer('src/xmlsec').find_module('meta').load_module('meta') +_xmlsec = Extension( + __name__, + sources=find_sources("./src"), + extra_compile_args=cflags, + libraries=list(config.get('libraries', [])), + library_dirs=list(config.get('library_dirs', [])), + include_dirs=list(config.get('include_dirs', [])), + define_macros=config['define_macros'] +) setup( - name='xmlsec', - version=meta.version, - description=meta.description, + name=__name__, + version=__version__, + description=__description__, + ext_modules=[_xmlsec], + author="Ryan Leckey", + author_email='support@mehcode.com', + maintainer='Bulat Gaifullin', + maintainer_email='gaifullinbf@gmail.com', + url='https://github.com/mehcode/python-xmlsec', + download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % __version__, + license='MIT', + keywords=["xmlsec"], classifiers=[ 'Development Status :: 3 - Alpha', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', - 'Programming Language :: Cython', + 'Programming Language :: C', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', 'Topic :: Text Processing :: Markup :: XML' ], - author='Ryan Leckey', - author_email='support@mehcode.com', - url='https://github.com/mehcode/python-xmlsec', - setup_requires=[ - 'setuptools_cython', - 'pkgconfig', - 'lxml >= 3.0', - ], - install_requires=[ - 'lxml >= 3.0', - ], - extras_require={ - 'test': ['pytest'] - }, - package_dir={'xmlsec': 'src/xmlsec'}, - packages=['xmlsec'], - ext_modules=[ - make_extension('xmlsec.constants'), - make_extension('xmlsec.utils'), - make_extension('xmlsec.tree'), - make_extension('xmlsec.key'), - make_extension('xmlsec.ds'), - make_extension('xmlsec.enc'), - make_extension('xmlsec.template'), - ] ) diff --git a/src/common.h b/src/common.h new file mode 100644 index 00000000..5f91bc2f --- /dev/null +++ b/src/common.h @@ -0,0 +1,30 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_COMMON_H__ +#define __PYXMLSEC_COMMON_H__ + +#include "debug.h" + +#ifndef MODULE_NAME +#define MODULE_NAME "xmlsec" +#endif + +#ifndef MODULE_DOC +#define MODULE_DOC "The tiny python wrapper around xmlsec1 library." +#endif + +#define JOIN(X,Y) DO_JOIN1(X,Y) +#define DO_JOIN1(X,Y) DO_JOIN2(X,Y) +#define DO_JOIN2(X,Y) X##Y + +#define DO_STRINGIFY(x) #x +#define STRINGIFY(x) DO_STRINGIFY(x) + +#endif //__PYXMLSEC_COMMON_H__ diff --git a/src/constants.c b/src/constants.c new file mode 100644 index 00000000..b5d7b8e4 --- /dev/null +++ b/src/constants.c @@ -0,0 +1,516 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "constants.h" + +#define PYXMLSEC_CONSTANTS_DOC "Various constants used by the library.\n" + +// destructor +static void PyXmlSec_Transform__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p", self); + Py_TYPE(self)->tp_free(self); +} + +// __str__ method +static PyObject* PyXmlSec_Transform__str__(PyObject* self) { + char buf[300]; + PyXmlSec_Transform* transform = (PyXmlSec_Transform*)(self); + snprintf(buf, sizeof(buf), "%s, %s", transform->id->name, transform->id->href); + return PyString_FromString(buf); +} + +static const char PyXmlSec_TransformNameGet__doc__[] = "The transform's name."; +static PyObject* PyXmlSec_TransformNameGet(PyXmlSec_Transform* self, void* closure) { + return PyString_FromString((const char*)self->id->name); +} + +static const char PyXmlSec_TransformHrefGet__doc__[] = "The transform's identification string (href)."; +static PyObject* PyXmlSec_TransformHrefGet(PyXmlSec_Transform* self, void* closure) { + return PyString_FromString((const char*)self->id->href); +} + +static const char PyXmlSec_TransformUsageGet__doc__[] = "The allowed transforms usages."; +static PyObject* PyXmlSec_TransformUsageGet(PyXmlSec_Transform* self, void* closure) { + return PyLong_FromUnsignedLong(self->id->usage); +} + +static PyGetSetDef PyXmlSec_TransformGetSet[] = { + { + "name", + (getter)PyXmlSec_TransformNameGet, + NULL, + (char*)PyXmlSec_TransformNameGet__doc__, + NULL + }, + { + "href", + (getter)PyXmlSec_TransformHrefGet, + NULL, + (char*)PyXmlSec_TransformHrefGet__doc__, + NULL + }, + { + "usage", + (getter)PyXmlSec_TransformUsageGet, + NULL, + (char*)PyXmlSec_TransformUsageGet__doc__, + NULL + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject _PyXmlSec_TransformType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) "constants.__Transform", /* tp_name */ + sizeof(PyXmlSec_Transform), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_Transform__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + PyXmlSec_Transform__str__, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "The xmlSecTransformId reflection", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_TransformGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_TransformType = &_PyXmlSec_TransformType; + +static PyObject* PyXmlSec_TransformNew(xmlSecTransformId id) { + PyXmlSec_Transform* transform = PyObject_New(PyXmlSec_Transform, PyXmlSec_TransformType); + if (transform != NULL) { + transform->id = id; + } + return (PyObject*)transform; +} + +// destructor +static void PyXmlSec_KeyData__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p", self); + Py_TYPE(self)->tp_free(self); +} + +// __str__ method +static PyObject* PyXmlSec_KeyData__str__(PyObject* self) { + char buf[300]; + PyXmlSec_KeyData* keydata = (PyXmlSec_KeyData*)(self); + snprintf(buf, sizeof(buf), "%s, %s", keydata->id->name, keydata->id->href); + return PyString_FromString(buf); +} + +static const char PyXmlSec_KeyDataNameGet__doc__[] = "The key data's name."; +static PyObject* PyXmlSec_KeyDataNameGet(PyXmlSec_KeyData* self, void* closure) { + return PyString_FromString((const char*)self->id->name); +} + +static const char PyXmlSec_KeyDataHrefGet__doc__[] = "The key data's identification string (href)."; +static PyObject* PyXmlSec_KeyDataHrefGet(PyXmlSec_KeyData* self, void* closure) { + return PyString_FromString((const char*)self->id->href); +} + +static PyGetSetDef PyXmlSec_KeyDataGetSet[] = { + { + "name", + (getter)PyXmlSec_KeyDataNameGet, + NULL, + (char*)PyXmlSec_KeyDataNameGet__doc__, + NULL + }, + { + "href", + (getter)PyXmlSec_KeyDataHrefGet, + NULL, + (char*)PyXmlSec_KeyDataHrefGet__doc__, + NULL + }, + {NULL} /* Sentinel */ +}; + +static PyTypeObject _PyXmlSec_KeyDataType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) "constants.__KeyData", /* tp_name */ + sizeof(PyXmlSec_KeyData), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_KeyData__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + PyXmlSec_KeyData__str__, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "The xmlSecKeyDataId reflection", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_KeyDataGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_KeyDataType = &_PyXmlSec_KeyDataType; + +static PyObject* PyXmlSec_KeyDataNew(xmlSecKeyDataId id) { + PyXmlSec_KeyData* keydata = PyObject_New(PyXmlSec_KeyData, PyXmlSec_KeyDataType); + if (keydata != NULL) { + keydata->id = id; + } + return (PyObject*)keydata; +} + +#ifdef PY3K +static PyModuleDef PyXmlSec_ConstantsModule = +{ + PyModuleDef_HEAD_INIT, + STRINGIFY(MODULE_NAME) ".constants", + PYXMLSEC_CONSTANTS_DOC, + -1, NULL, NULL, NULL, NULL, NULL +}; +#endif // PY3K + +// initialize constants module and registers it base package +int PyXmlSec_ConstantsModule_Init(PyObject* package) { + PyObject* constants = NULL; + PyObject* nsCls = NULL; + PyObject* nodeCls = NULL; + PyObject* transformCls = NULL; + PyObject* encryptionTypeCls = NULL; + PyObject* keyFormatCls = NULL; + PyObject* keyDataCls = NULL; + PyObject* keyDataTypeCls = NULL; + PyObject* tmp = NULL; + +#ifdef PY3K + constants = PyModule_Create(&PyXmlSec_ConstantsModule); +#else + constants = Py_InitModule3(STRINGIFY(MODULE_NAME) ".constants", NULL, PYXMLSEC_CONSTANTS_DOC); + Py_XINCREF(constants); +#endif + + if (!constants) return -1; + + if (PyType_Ready(PyXmlSec_TransformType) < 0) goto ON_FAIL; + if (PyType_Ready(PyXmlSec_KeyDataType) < 0) goto ON_FAIL; + +#define PYXMLSEC_ADD_INT_CONSTANT(name) PyModule_AddIntConstant(constants, STRINGIFY(name), JOIN(xmlSec, name)) + + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageUnknown) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageDSigTransform) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageC14NMethod) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageDigestMethod) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageSignatureMethod) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageEncryptionMethod) < 0) goto ON_FAIL; + if (PYXMLSEC_ADD_INT_CONSTANT(TransformUsageAny) < 0) goto ON_FAIL; + +#undef PYXMLSEC_ADD_INT_CONSTANT + +#define PYXMLSEC_DECLARE_NAMESPACE(var, name) \ + if (!(var = PyCreateDummyObject(name))) goto ON_FAIL; \ + if (PyModule_AddObject(package, name, var) < 0) goto ON_FAIL; \ + Py_INCREF(var); // add object steels reference + +#define PYXMLSEC_CLOSE_NAMESPACE(var) \ + Py_DECREF(var); var = NULL // compensate add ref from declare namespace + +#define PYXMLSEC_ADD_CONSTANT(ns, name, lname) \ + if (tmp == NULL) goto ON_FAIL; \ + if (PyModule_AddObject(constants, STRINGIFY(name), tmp) < 0) goto ON_FAIL; \ + Py_INCREF(tmp); \ + if (PyModule_AddObject(ns, lname, tmp) < 0) goto ON_FAIL; \ + tmp = NULL; + + +#define PYXMLSEC_ADD_NS_CONSTANT(name, lname) \ + tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + PYXMLSEC_ADD_CONSTANT(nsCls, name, lname); + + // namespaces + PYXMLSEC_DECLARE_NAMESPACE(nsCls, "Namespace"); + + PYXMLSEC_ADD_NS_CONSTANT(Ns, "BASE"); + PYXMLSEC_ADD_NS_CONSTANT(DSigNs, "DS"); + PYXMLSEC_ADD_NS_CONSTANT(EncNs, "ENC"); + PYXMLSEC_ADD_NS_CONSTANT(XkmsNs, "XKMS"); + PYXMLSEC_ADD_NS_CONSTANT(XPathNs, "XPATH"); + PYXMLSEC_ADD_NS_CONSTANT(XPath2Ns, "XPATH2"); + PYXMLSEC_ADD_NS_CONSTANT(XPointerNs, "XPOINTER"); + PYXMLSEC_ADD_NS_CONSTANT(Soap11Ns, "SOAP11"); + PYXMLSEC_ADD_NS_CONSTANT(Soap12Ns, "SOAP12"); + + PYXMLSEC_CLOSE_NAMESPACE(nsCls); + +#undef PYXMLSEC_ADD_NS_CONSTANT + + +#define PYXMLSEC_ADD_ENC_CONSTANT(name, lname) \ + tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + PYXMLSEC_ADD_CONSTANT(encryptionTypeCls, name, lname); + + // encryption type + PYXMLSEC_DECLARE_NAMESPACE(encryptionTypeCls, "EncryptionType"); + + PYXMLSEC_ADD_ENC_CONSTANT(TypeEncContent, "CONTENT"); + PYXMLSEC_ADD_ENC_CONSTANT(TypeEncElement, "ELEMENT"); + + PYXMLSEC_CLOSE_NAMESPACE(encryptionTypeCls); + +#undef PYXMLSEC_ADD_ENC_CONSTANT + + +#define PYXMLSEC_ADD_NODE_CONSTANT(name, lname) \ + tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + PYXMLSEC_ADD_CONSTANT(nodeCls, name, lname); + + // node + PYXMLSEC_DECLARE_NAMESPACE(nodeCls, "Node"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeSignature, "SIGNATURE"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeSignedInfo, "SIGNED_INFO"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeCanonicalizationMethod, "CANONICALIZATION_METHOD"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeSignatureMethod, "SIGNATURE_METHOD"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeSignatureValue, "SIGNATURE_VALUE"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeSignatureProperties, "SIGNATURE_PROPERTIES"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeDigestMethod, "DIGEST_METHOD"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeDigestValue, "DIGEST_VALUE"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeObject, "OBJECT"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeManifest, "MANIFEST"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeEncryptedData, "ENCRYPTED_DATA"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeEncryptedKey, "ENCRYPTED_KEY"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeEncryptionMethod, "ENCRYPTION_METHOD"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeEncryptionProperty, "ENCRYPTION_PROPERTY"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeEncryptionProperties, "ENCRYPTION_PROPERTIES"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeCipherData, "CIPHER_DATA"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeCipherValue, "CIPHER_VALUE"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeCipherReference, "CIPHER_REFERENCE"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeDataReference, "DATA_REFERENCE"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyReference, "KEY_REFERENCE"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeReferenceList, "REFERENCE_LIST"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyInfo, "KEY_INFO"); + + PYXMLSEC_CLOSE_NAMESPACE(nodeCls); +#undef PYXMLSEC_ADD_NODE_CONSTANT + + +#define PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(name, lname) \ + tmp = PyLong_FromUnsignedLong((unsigned long)(JOIN(xmlSec, name))); \ + PYXMLSEC_ADD_CONSTANT(keyFormatCls, name, lname); + + // key format + PYXMLSEC_DECLARE_NAMESPACE(keyFormatCls, "KeyFormat"); + + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatUnknown, "UNKNOWN"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatBinary, "BINARY"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatPem, "PEM"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatDer, "DER"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatPkcs8Pem, "PKCS8_PEM"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatPkcs8Der, "PKCS8_DER");; + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatPkcs12, "PKCS12_PEM"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatCertPem, "CERT_PEM"); + PYXMLSEC_ADD_KEY_FORMAT_CONSTANT(KeyDataFormatCertDer, "CERT_DER"); + + PYXMLSEC_CLOSE_NAMESPACE(keyFormatCls); +#undef PYXMLSEC_ADD_KEY_FORMAT_CONSTANT + + +#define PYXMLSEC_ADD_KEY_TYPE_CONSTANT(name, lname) \ + tmp = PyLong_FromUnsignedLong((unsigned long)(JOIN(xmlSec, name))); \ + PYXMLSEC_ADD_CONSTANT(keyDataTypeCls, name, lname); + + // key data type + PYXMLSEC_DECLARE_NAMESPACE(keyDataTypeCls, "KeyDataType"); + + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeUnknown, "UNKNOWN"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeNone, "NONE"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePublic, "PUBLIC"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePrivate, "PRIVATE"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeSymmetric, "SYMMETRIC"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeSession, "SESSION");; + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePermanent, "PERMANENT"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeTrusted, "TRUSTED"); + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeAny, "ANY"); + + PYXMLSEC_CLOSE_NAMESPACE(keyDataTypeCls); +#undef PYXMLSEC_ADD_KEY_TYPE_CONSTANT + + +#define PYXMLSEC_ADD_KEYDATA_CONSTANT(name, lname) \ + tmp = PyXmlSec_KeyDataNew(xmlSec ## name ## Id); \ + PYXMLSEC_ADD_CONSTANT(keyDataCls, name, lname); + + // keydata + PYXMLSEC_DECLARE_NAMESPACE(keyDataCls, "KeyData"); + + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataName, "NAME") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataValue, "VALUE") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataRetrievalMethod, "RETRIEVALMETHOD") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEncryptedKey, "ENCRYPTEDKEY") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataAes, "AES") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDes, "DES") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDsa, "DSA") +#if XMLSEC_VERSION_HEX > 306 + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEcdsa, "ECDSA") +#endif + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataHmac, "HMAC") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataRsa, "RSA") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataX509, "X509") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataRawX509Cert, "RAWX509CERT") + + PYXMLSEC_CLOSE_NAMESPACE(keyDataCls); +#undef PYXMLSEC_ADD_KEYDATA_CONSTANT + + +#define PYXMLSEC_ADD_TRANSFORM_CONSTANT(name, lname) \ + tmp = PyXmlSec_TransformNew(xmlSec ## name ## Id); \ + PYXMLSEC_ADD_CONSTANT(transformCls, name, lname); + + // transforms + PYXMLSEC_DECLARE_NAMESPACE(transformCls, "Transform"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformInclC14N, "C14N"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformInclC14NWithComments, "C14N_COMMENTS"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformInclC14N11, "C14N11"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformInclC14N11WithComments, "C14N11_COMMENTS"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformExclC14N, "EXCL_C14N"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformExclC14NWithComments, "EXCL_C14N_COMMENTS"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEnveloped, "ENVELOPED"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPath, "XPATH"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPath2, "XPATH2"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPointer, "XPOINTER"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXslt, "XSLT"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRemoveXmlTagsC14N, "REMOVE_XML_TAGS_C14N"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformVisa3DHack, "VISA3D_HACK"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes128Cbc, "AES128"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes192Cbc, "AES192"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes256Cbc, "AES256"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWAes128, "KW_AES128"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWAes192, "KW_AES192"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWAes256, "KW_AES256"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDes3Cbc, "DES3"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWDes3, "KW_DES3"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDsaSha1, "DSA_SHA1"); + +#if XMLSEC_VERSION_HEX > 306 + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha1, "ECDSA_SHA1"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha224, "ECDSA_SHA224"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha256, "ECDSA_SHA256"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha384, "ECDSA_SHA384"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha512, "ECDSA_SHA512"); +#endif + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacMd5, "HMAC_MD5"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacRipemd160, "HMAC_RIPEMD160"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha1, "HMAC_SHA1"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha224, "HMAC_SHA224"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha256, "HMAC_SHA256"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha384, "HMAC_SHA384"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha512, "HMAC_SHA512"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaMd5, "RSA_MD5"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaRipemd160, "RSA_RIPEMD160"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha1, "RSA_SHA1"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha224, "RSA_SHA224"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha256, "RSA_SHA256"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha384, "RSA_SHA384"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha512, "RSA_SHA512"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaPkcs1, "RSA_PKCS1"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaOaep, "RSA_OAEP"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformMd5, "MD5"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRipemd160, "RIPEMD160"); + + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha1, "SHA1"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha224, "SHA224"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha256, "SHA256"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha384, "SHA384"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha512, "SHA512"); + + PYXMLSEC_CLOSE_NAMESPACE(transformCls); + +#undef PYXMLSEC_ADD_TRANSFORM_CONSTANT +#undef PYXMLSEC_ADD_CONSTANT +#undef PYXMLSEC_DECLARE_NAMESPACE + + if (PyModule_AddObject(package, "constants", constants) < 0) goto ON_FAIL; + + return 0; +ON_FAIL: + Py_XDECREF(tmp); + Py_XDECREF(nsCls); + Py_XDECREF(nodeCls); + Py_XDECREF(transformCls); + Py_XDECREF(encryptionTypeCls); + Py_XDECREF(keyFormatCls); + Py_XDECREF(keyDataCls); + Py_XDECREF(keyDataTypeCls); + Py_DECREF(constants); + + return -1; +} diff --git a/src/constants.h b/src/constants.h new file mode 100644 index 00000000..a9a5e716 --- /dev/null +++ b/src/constants.h @@ -0,0 +1,31 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_CONSTANTS_H__ +#define __PYXMLSEC_CONSTANTS_H__ + +#include "platform.h" + +#include +#include + +typedef struct { + PyObject_HEAD + xmlSecTransformId id; +} PyXmlSec_Transform; + +typedef struct { + PyObject_HEAD + xmlSecKeyDataId id; +} PyXmlSec_KeyData; + +extern PyTypeObject* PyXmlSec_TransformType; +extern PyTypeObject* PyXmlSec_KeyDataType; + +#endif //__PYXMLSEC_CONSTANTS_H__ diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 00000000..0604a462 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,23 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_DEBUG_H__ +#define __PYXMLSEC_DEBUG_H__ + +#ifdef PYXMLSEC_ENABLE_DEBUG + +#include +#define PYXMLSEC_DEBUG(fmt) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__) +#define PYXMLSEC_DEBUGF(fmt, ...) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#else +#define PYXMLSEC_DEBUG(...) +#define PYXMLSEC_DEBUGF(...) +#endif // PYXMLSEC_ENABLE_DEBUG + +#endif // __PYXMLSEC_DEBUG_H__ diff --git a/src/ds.c b/src/ds.c new file mode 100644 index 00000000..7a62715b --- /dev/null +++ b/src/ds.c @@ -0,0 +1,561 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "platform.h" +#include "exception.h" +#include "constants.h" +#include "keys.h" +#include "lxml.h" + +#include + +typedef struct { + PyObject_HEAD + xmlSecDSigCtxPtr handle; + PyXmlSec_KeysManager* manager; +} PyXmlSec_SignatureContext; + +static PyObject* PyXmlSec_SignatureContext__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)PyType_GenericNew(type, args, kwargs); + PYXMLSEC_DEBUGF("%p: new sign context", ctx); + if (ctx != NULL) { + ctx->handle = NULL; + ctx->manager = NULL; + } + return (PyObject*)(ctx); +} + +static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "manager", NULL}; + + PyXmlSec_KeysManager* manager = NULL; + PYXMLSEC_DEBUGF("%p: init sign context", self); + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { + return -1; + } + PYXMLSEC_DEBUGF("%p", manager); + ctx->handle = xmlSecDSigCtxCreate(manager != NULL ? manager->handle : NULL); + if (ctx->handle == NULL) { + PyXmlSec_SetLastError("failed to create the digital signature context"); + return -1; + } + Py_XINCREF(manager); + ctx->manager = manager; + return 0; +} + +static void PyXmlSec_SignatureContext__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p: delete sign context", self); + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; + if (ctx->handle != NULL) { + xmlSecDSigCtxDestroy(ctx->handle); + } + // release manager object + Py_XDECREF(ctx->manager); + Py_TYPE(self)->tp_free(self); +} + +static const char PyXmlSec_SignatureContextKey__doc__[] = "Signature key.\n"; +static PyObject* PyXmlSec_SignatureContextKeyGet(PyObject* self, void* closure) { + PyXmlSec_Key* key = PyXmlSec_NewKey(); + key->handle = ((PyXmlSec_SignatureContext*)self)->handle->signKey; + key->is_own = 0; + return (PyObject*)key; +} + +static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void* closure) { + PYXMLSEC_DEBUGF("%p, %p", self, value); + if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { + PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); + return -1; + } + PyXmlSec_Key* key = (PyXmlSec_Key*)value; + if (key->handle == NULL) { + PyErr_SetString(PyExc_TypeError, "empty key."); + return -1; + } + + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; + if (ctx->handle->signKey != NULL) { + xmlSecKeyDestroy(ctx->handle->signKey); + } + + ctx->handle->signKey = xmlSecKeyDuplicate(key->handle); + if (ctx->handle->signKey == NULL) { + PyXmlSec_SetLastError("failed to duplicate key"); + return -1; + } + return 0; +} + +static const char PyXmlSec_SignatureContextRegisterId__doc__[] = "Register new id.\n"; +static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "node", "id_attr", "id_ns", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* id_attr = "ID"; + const char* id_ns = NULL; + + xmlChar* name = NULL; + xmlAttrPtr attr = NULL; + + PYXMLSEC_DEBUGF("%p: register id - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sz:register_id", kwlist, + PyXmlSec_LxmlElementConverter, &node, &id_attr, &id_ns)) + { + goto ON_FAIL; + } + + if (id_ns != NULL) { + attr = xmlHasNsProp(node->_c_node, XSTR(id_attr), XSTR(id_ns)); + } else { + attr = xmlHasProp(node->_c_node, XSTR(id_attr)); + } + + if (attr == NULL || attr->children == NULL) { + PyErr_SetString(PyXmlSec_Error, "missing attribute."); + goto ON_FAIL; + } + + name = xmlNodeListGetString(node->_c_node->doc, attr->children, 1); + xmlAttrPtr tmpAttr = xmlGetID(node->_c_node->doc, name); + if (tmpAttr != attr) { + if (tmpAttr != NULL) { + PyErr_SetString(PyXmlSec_Error, "duplicated id."); + goto ON_FAIL; + } + + Py_BEGIN_ALLOW_THREADS; + xmlAddID(NULL, node->_c_node->doc, name, attr); + Py_END_ALLOW_THREADS; + } + + xmlFree(name); + PYXMLSEC_DEBUGF("%p: register id - ok", self); + Py_RETURN_NONE; +ON_FAIL: + xmlFree(name); + PYXMLSEC_DEBUGF("%p: register id - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextSign__doc__[] = "Sign according to the signature template.\n"; +static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUGF("%p: sign - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:sign", kwlist, PyXmlSec_LxmlElementConverter, &node)) { + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecDSigCtxSign(((PyXmlSec_SignatureContext*)self)->handle, node->_c_node); + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("failed to sign"); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: sign - ok", self); + Py_RETURN_NONE; + +ON_FAIL: + PYXMLSEC_DEBUGF("%p: sign - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextVerify__doc__[] = "Verify according to the signature template.\n"; +static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUGF("%p: verify - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:verify", kwlist, PyXmlSec_LxmlElementConverter, &node)) { + goto ON_FAIL; + } + + xmlSecDSigCtxPtr handle = ((PyXmlSec_SignatureContext*)self)->handle; + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecDSigCtxVerify(handle, node->_c_node); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("failed to verify"); + goto ON_FAIL; + } + if (handle->status != xmlSecDSigStatusSucceeded) { + PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid."); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: verify - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: verify - fail", self); + return NULL; +} + +// common helper for operations binary_verify and binary_sign +static int PyXmlSec_ProcessSignBinary(xmlSecDSigCtxPtr ctx, const xmlSecByte* data, xmlSecSize data_size, xmlSecTransformId method) { + if (!(method->usage & xmlSecTransformUsageSignatureMethod)) { + PyErr_SetString(PyXmlSec_Error, "incompatible signature method"); + return -1; + } + + if (ctx->signKey == NULL) { + PyErr_SetString(PyXmlSec_Error, "Sign key is not specified."); + } + + if (ctx->signMethod != NULL) { + PyErr_SetString(PyXmlSec_Error, "Signature context already used; it is designed for one use only."); + return -1; + } + + ctx->signMethod = xmlSecTransformCtxCreateAndAppend(&(ctx->transformCtx), method); + if (ctx->signMethod == NULL) { + PyXmlSec_SetLastError("could not create signature transform."); + return -1; + } + + int rv; + + ctx->signMethod->operation = ctx->operation; + xmlSecTransformSetKeyReq(ctx->signMethod, &(ctx->keyInfoReadCtx.keyReq)); + rv = xmlSecKeyMatch(ctx->signKey, NULL, &(ctx->keyInfoReadCtx.keyReq)); + if (rv != 1) { + PyXmlSec_SetLastError("inappropriate key type."); + return -1; + } + + rv = xmlSecTransformSetKey(ctx->signMethod, ctx->signKey); + if (rv < 0) { + PyXmlSec_SetLastError("cannot set key."); + return -1; + } + ctx->transformCtx.result = NULL; + ctx->transformCtx.status = xmlSecTransformStatusNone; + + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecTransformCtxBinaryExecute(&(ctx->transformCtx), data, data_size); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("failed to transform."); + return -1; + } + ctx->result = ctx->transformCtx.result; + + return 0; +} + +static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \ + "Sign binary data *data* with *algorithm* and return the signature.\n"; +static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "bytes", "transform", NULL}; + + PyXmlSec_Transform* transform = NULL; + const char* data = NULL; + Py_ssize_t data_size = 0; + + PYXMLSEC_DEBUGF("%p: sign_binary - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O!:sign_binary", kwlist, + &data, &data_size, PyXmlSec_TransformType, &transform)) + { + goto ON_FAIL; + } + + xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; + ctx->operation = xmlSecTransformOperationSign; + + if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) { + goto ON_FAIL; + } + + PYXMLSEC_DEBUGF("%p: sign_binary - ok", self); + return PyBytes_FromStringAndSize( + (const char*)xmlSecBufferGetData(ctx->result), (Py_ssize_t)xmlSecBufferGetSize(ctx->result) + ); +ON_FAIL: + PYXMLSEC_DEBUGF("%p: sign_binary - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \ + "Sign binary data *data* with *algorithm* and return the signature.\n"; +static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "bytes", "transform", "signature", NULL}; + + PyXmlSec_Transform* transform = NULL; + const char* data = NULL; + Py_ssize_t data_size = 0; + const char* sign = NULL; + Py_ssize_t sign_size = 0; + + PYXMLSEC_DEBUGF("%p: verify binary - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O!s#:verify_binary", kwlist, + &data, &data_size, PyXmlSec_TransformType, &transform, &sign, &sign_size)) + { + goto ON_FAIL; + } + + xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; + ctx->operation = xmlSecTransformOperationVerify; + if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) { + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecTransformVerify(ctx->signMethod, (const xmlSecByte*)sign, (xmlSecSize)sign_size, &(ctx->transformCtx)); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError2(PyXmlSec_VerificationError, "Cannot verify signature."); + goto ON_FAIL; + } + + if (ctx->signMethod->status != xmlSecTransformStatusOk) { + PyXmlSec_SetLastError2(PyXmlSec_VerificationError, "Signature is invalid."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUGF("%p: verify binary - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: verify binary - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \ + "Enables use of *t* as reference transform.\n"\ + "Note: by default, all transforms are enabled. The first call of\n"\ + "`enable_reference_transform` will switch to explicitly enabled transforms.\n"; +static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "transform", NULL}; + + PyXmlSec_Transform* transform = NULL; + + PYXMLSEC_DEBUGF("%p: enable_reference_transform - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_reference_transform", kwlist, PyXmlSec_TransformType, &transform)) + { + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecDSigCtxEnableReferenceTransform(((PyXmlSec_SignatureContext*)self)->handle, transform->id); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("cannot enable reference transform."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUGF("%p: enable_reference_transform - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: enable_reference_transform - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \ + "Enables use of *t* as signature transform.\n"\ + "Note: by default, all transforms are enabled. The first call of\n"\ + "`enable_signature_transform` will switch to explicitly enabled transforms.\n"; +static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "transform", NULL}; + + PyXmlSec_Transform* transform = NULL; + + PYXMLSEC_DEBUGF("%p: enable_signature_transform - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_signature_transform", kwlist, PyXmlSec_TransformType, &transform)) { + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecDSigCtxEnableSignatureTransform(((PyXmlSec_SignatureContext*)self)->handle, transform->id); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("cannot enable signature transform."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUGF("%p: enable_signature_transform - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: enable_signature_transform - fail", self); + return NULL; +} + +static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \ + "Adds selected *KeyData* to the list of enabled key data list.\n"; +static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "keydata_list", NULL}; + + PyObject* keydata_list = NULL; + PyObject* iter = NULL; + PyObject* item = NULL; + + PYXMLSEC_DEBUGF("%p: set_enabled_key_data - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_enabled_key_data", kwlist, &keydata_list)) { + goto ON_FAIL; + } + if ((iter = PyObject_GetIter(keydata_list)) == NULL) goto ON_FAIL; + + xmlSecPtrListPtr enabled_list = &(((PyXmlSec_SignatureContext*)self)->handle->keyInfoReadCtx.enabledKeyData); + xmlSecPtrListEmpty(enabled_list); + + while ((item = PyIter_Next(iter)) != NULL) { + if (!PyObject_IsInstance(item, (PyObject*)PyXmlSec_KeyDataType)) { + PyErr_SetString(PyExc_TypeError, "expected list of KeyData constants."); + goto ON_FAIL; + } + if (xmlSecPtrListAdd(enabled_list, (xmlSecPtr)((PyXmlSec_KeyData*)item)->id) < 0) { + PyXmlSec_SetLastError("cannot set enabled key."); + goto ON_FAIL; + } + Py_DECREF(item); + } + Py_DECREF(iter); + + PYXMLSEC_DEBUGF("%p: set_enabled_key_data - ok", self); + + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: set_enabled_key_data - fail", self); + Py_XDECREF(item); + Py_XDECREF(iter); + return NULL; +} + +static PyGetSetDef PyXmlSec_SignatureContextGetSet[] = { + { + "key", + (getter)PyXmlSec_SignatureContextKeyGet, + (setter)PyXmlSec_SignatureContextKeySet, + (char*)PyXmlSec_SignatureContextKey__doc__, + NULL + }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef PyXmlSec_SignatureContextMethods[] = { + { + "register_id", + (PyCFunction)PyXmlSec_SignatureContextRegisterId, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextRegisterId__doc__, + }, + { + "sign", + (PyCFunction)PyXmlSec_SignatureContextSign, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextSign__doc__ + }, + { + "verify", + (PyCFunction)PyXmlSec_SignatureContextVerify, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextVerify__doc__ + }, + { + "sign_binary", + (PyCFunction)PyXmlSec_SignatureContextSignBinary, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextSignBinary__doc__ + }, + { + "verify_binary", + (PyCFunction)PyXmlSec_SignatureContextVerifyBinary, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextVerifyBinary__doc__ + }, + { + "enable_reference_transform", + (PyCFunction)PyXmlSec_SignatureContextEnableReferenceTransform, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextEnableReferenceTransform__doc__ + }, + { + "enable_signature_transform", + (PyCFunction)PyXmlSec_SignatureContextEnableSignatureTransform, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextEnableSignatureTransform__doc__, + }, + { + "set_enabled_key_data", + (PyCFunction)PyXmlSec_SignatureContextSetEnabledKeyData, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_SignatureContextSetEnabledKeyData__doc__, + }, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject _PyXmlSec_SignatureContextType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) ".SignatureContext", /* tp_name */ + sizeof(PyXmlSec_SignatureContext), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_SignatureContext__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XML Digital Signature implementation", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyXmlSec_SignatureContextMethods, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_SignatureContextGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + PyXmlSec_SignatureContext__init__, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyXmlSec_SignatureContext__new__, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_SignatureContextType = &_PyXmlSec_SignatureContextType; + +int PyXmlSec_DSModule_Init(PyObject* package) { + if (PyType_Ready(PyXmlSec_SignatureContextType) < 0) goto ON_FAIL; + + // since objects is created as static objects, need to increase refcount to prevent deallocate + Py_INCREF(PyXmlSec_SignatureContextType); + + if (PyModule_AddObject(package, "SignatureContext", (PyObject*)PyXmlSec_SignatureContextType) < 0) goto ON_FAIL; + return 0; +ON_FAIL: + return -1; +} diff --git a/src/enc.c b/src/enc.c new file mode 100644 index 00000000..3c8fc2ec --- /dev/null +++ b/src/enc.c @@ -0,0 +1,452 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "platform.h" +#include "exception.h" +#include "constants.h" +#include "keys.h" +#include "lxml.h" + +#include + +typedef struct { + PyObject_HEAD + xmlSecEncCtxPtr handle; + PyXmlSec_KeysManager* manager; +} PyXmlSec_EncryptionContext; + +static PyObject* PyXmlSec_EncryptionContext__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)PyType_GenericNew(type, args, kwargs); + PYXMLSEC_DEBUGF("%p: new sign context", ctx); + if (ctx != NULL) { + ctx->handle = NULL; + ctx->manager = NULL; + } + return (PyObject*)(ctx); +} + +static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "manager", NULL}; + + PyXmlSec_KeysManager* manager = NULL; + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + PYXMLSEC_DEBUGF("%p: init sign context", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { + return -1; + } + + PYXMLSEC_DEBUGF("%p", manager); + ctx->handle = xmlSecEncCtxCreate(manager != NULL ? manager->handle : NULL); + if (ctx->handle == NULL) { + PyXmlSec_SetLastError("failed to create the digital signature context"); + return -1; + } + Py_XINCREF(manager); + ctx->manager = manager; + return 0; +} + +static void PyXmlSec_EncryptionContext__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p: delete sign context", self); + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + if (ctx->handle != NULL) { + xmlSecEncCtxDestroy(ctx->handle); + } + // release manager object + Py_XDECREF(ctx->manager); + Py_TYPE(self)->tp_free(self); +} + +static const char PyXmlSec_EncryptionContextKey__doc__[] = "Encryption key.\n"; +static PyObject* PyXmlSec_EncryptionContextKeyGet(PyObject* self, void* closure) { + PyXmlSec_Key* key = PyXmlSec_NewKey(); + key->handle = ((PyXmlSec_EncryptionContext*)self)->handle->encKey; + key->is_own = 0; + return (PyObject*)key; +} + +static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, void* closure) { + PYXMLSEC_DEBUGF("%p, %p", self, value); + if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { + PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); + return -1; + } + + xmlSecKeyPtr keyHandle = ((PyXmlSec_Key*)value)->handle; + if (keyHandle == NULL) { + PyErr_SetString(PyExc_TypeError, "empty key."); + return -1; + } + + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + if (ctx->handle->encKey != NULL) { + xmlSecKeyDestroy(ctx->handle->encKey); + } + + ctx->handle->encKey = xmlSecKeyDuplicate(keyHandle); + if (ctx->handle->encKey == NULL) { + PyXmlSec_SetLastError("failed to duplicate key"); + return -1; + } + return 0; +} + +static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \ + "Encrypts binary *data* according to `EncryptedData` template *template*\n"\ + "returns the resulting `EncryptedData` subtree.\n" \ + "Note: *template* is modified in place.\n"; +static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "template", "data", NULL}; + + PyXmlSec_LxmlElementPtr template = NULL; + const char* data = NULL; + Py_ssize_t data_size = 0; + + PYXMLSEC_DEBUGF("%p: encrypt_binary - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s#:encrypt_binary", kwlist, + PyXmlSec_LxmlElementConverter, &template, &data, &data_size)) + { + goto ON_FAIL; + } + xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecEncCtxBinaryEncrypt(ctx, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("failed to encrypt binary"); + goto ON_FAIL; + } + Py_INCREF(template); + PYXMLSEC_DEBUGF("%p: encrypt_binary - ok", self); + + return (PyObject*)template; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: encrypt_binary - fail", self); + return NULL; +} + +// release the replaced nodes in a way safe for `lxml` +static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocumentPtr doc) { + // release the replaced nodes in a way safe for `lxml` + xmlNodePtr n = ctx->replacedNodeList; + xmlNodePtr nn; + while (n != NULL) { + nn = n->next; + // if n has references, it will not be deleted + Py_XDECREF(PyXmlSec_elementFactory(doc, n)); + n = nn; + } + ctx->replacedNodeList = NULL; +} + +static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \ + "Encrpyts *node* using *template*.\n" \ + "Returns the resulting `EncryptedData` element.\n\n"\ + "Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\ + "(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\ + "It must have one of these two values (or an exception is raised).\n"\ + "The operation modifies the tree containing *node* in a way that\n"\ + "`lxml` references to or into this tree may see a surprising state.\n"\ + "You should no longer rely on them. Especially, you should use\n"\ + "`getroottree()` on the result to obtain the encrypted result tree.\n"; +static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "template", "node", NULL}; + + PyXmlSec_LxmlElementPtr template = NULL; + PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr xnew_node = NULL; + xmlChar* tmpType = NULL; + + PYXMLSEC_DEBUGF("%p: encrypt_xml - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:encrypt_xml", kwlist, + PyXmlSec_LxmlElementConverter, &template, PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + tmpType = xmlGetProp(template->_c_node, XSTR("Type")); + if (tmpType == NULL || !(xmlStrEqual(tmpType, xmlSecTypeEncElement) || xmlStrEqual(tmpType, xmlSecTypeEncContent))) { + PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`)"); + goto ON_FAIL; + } + + // `xmlSecEncCtxXmlEncrypt` will replace the subtree rooted + // at `node._c_node` or its children by an extended subtree rooted at "c_node". + // We set `XMLSEC_ENC_RETURN_REPLACED_NODE` to prevent deallocation + // of the replaced node. This is important as `node` is still referencing it + xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; + ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; + int rv = 0; + + // try to do all actions whithin single python-free section + // rv has the following codes, 1 - failed to copy node, -1 - op failed, 0 - success + Py_BEGIN_ALLOW_THREADS; + if (template->_doc->_c_doc != node->_doc->_c_doc) { + // `xmlSecEncCtxEncrypt` expects *template* to belong to the document of *node* + // if this is not the case, we copy the `libxml2` subtree there. + xnew_node = xmlDocCopyNode(template->_c_node, node->_doc->_c_doc, 1); // recursive + if (xnew_node == NULL) { + rv = 1; + } + } + if (rv == 0 && xmlSecEncCtxXmlEncrypt(ctx, xnew_node != NULL ? xnew_node: template->_c_node, node->_c_node) < 0) { + rv = -1; + if (xnew_node != NULL) { + xmlFreeNode(xnew_node); + xnew_node = NULL; + } + } + Py_END_ALLOW_THREADS; + + PyXmlSec_ClearReplacedNodes(ctx, node->_doc); + + if (rv != 0) { + if (rv > 0) { + PyErr_SetString(PyXmlSec_InternalError, "could not copy template tree"); + } else { + PyXmlSec_SetLastError("failed to encrypt xml"); + } + goto ON_FAIL; + } + + xmlFree(tmpType); + PYXMLSEC_DEBUGF("%p: encrypt_xml - ok", self); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, xnew_node != NULL ? xnew_node : template->_c_node); +ON_FAIL: + PYXMLSEC_DEBUGF("%p: encrypt_xml - fail", self); + xmlFree(tmpType); + return NULL; +} + +static const char PyXmlSec_EncryptionContextEncryptUri__doc__[] = \ + "Encrypts binary data obtained from *uri* according to *template*.\n"; +static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "template", "uri", NULL}; + + PyXmlSec_LxmlElementPtr template = NULL; + const char* uri = NULL; + + PYXMLSEC_DEBUGF("%p: encrypt_uri - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s:encrypt_uri", kwlist, PyXmlSec_LxmlElementConverter, &template, &uri)) { + goto ON_FAIL; + } + + xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecEncCtxUriEncrypt(ctx, template->_c_node, (const xmlSecByte*)uri); + Py_END_ALLOW_THREADS; + + if (rv < 0) { + PyXmlSec_SetLastError("failed to encrypt URI"); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: encrypt_uri - ok", self); + Py_INCREF(template); + return (PyObject*)template; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: encrypt_uri - fail", self); + return NULL; +} + +static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \ + "Decrypts *node* (an `EncryptedData` element) and return the result.\n"\ + "The decryption may result in binary data or an XML subtree.\n"\ + "In the former case, the binary data is returned. In the latter case,\n"\ + "the input tree is modified and a reference to the decrypted XML subtree is returned.\n"\ + "If the operation modifies the tree, `lxml` references to or into this tree may see a surprising state.\n"\ + "You should no longer rely on them. Especially, you should use `getroottree()` on the result\n"\ + "to obtain the decrypted result tree.\n"; +static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PyObject* node_num = NULL; + PyObject* parent = NULL; + + + PYXMLSEC_DEBUGF("%p: decrypt - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:decrypt", kwlist, PyXmlSec_LxmlElementConverter, &node)) { + goto ON_FAIL; + } + + xmlNodePtr xparent = node->_c_node->parent; + if (xparent != NULL && !_isElement(xparent)) { + xparent = NULL; + } + + if (xparent != NULL) { + parent = (PyObject*)PyXmlSec_elementFactory(node->_doc, xparent); + if (parent == NULL) { + PyErr_SetString(PyXmlSec_InternalError, "failed to construct parent"); + goto ON_FAIL; + } + // get index of node + node_num = PyObject_CallMethod(parent, "index", "O", node); + PYXMLSEC_DEBUGF("%p, %p", parent, node_num); + } + + xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; + ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; + int rv; + + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecEncCtxDecrypt(ctx, node->_c_node); + Py_END_ALLOW_THREADS; + + PyXmlSec_ClearReplacedNodes(ctx, node->_doc); + + if (rv < 0) { + PyXmlSec_SetLastError("failed to decrypt"); + goto ON_FAIL; + } + + if (!ctx->resultReplaced) { + Py_XDECREF(node_num); + Py_XDECREF(parent); + PYXMLSEC_DEBUGF("%p: decrypt - ok", self); + return PyBytes_FromStringAndSize( + (const char*)xmlSecBufferGetData(ctx->result), (Py_ssize_t)xmlSecBufferGetSize(ctx->result) + ); + } + + if (xparent != NULL) { + xmlChar* ttype = xmlGetProp(node->_c_node, XSTR("Type")); + int notContent = (ttype == NULL || !xmlStrEqual(ttype, xmlSecTypeEncContent)); + xmlFree(ttype); + + if (notContent) { + PyObject* tmp = PyObject_GetItem(parent, node_num); + if (tmp == NULL) goto ON_FAIL; + Py_DECREF(parent); + parent = tmp; + } + Py_DECREF(node_num); + PYXMLSEC_DEBUGF("%p: decrypt - ok", self); + return parent; + } + + // root has been replaced + xmlNodePtr root = xmlDocGetRootElement(node->_doc->_c_doc); + if (root == NULL) { + PyErr_SetString(PyXmlSec_Error, "decryption resulted in a non well formed document"); + goto ON_FAIL; + } + + Py_XDECREF(node_num); + Py_XDECREF(parent); + + PYXMLSEC_DEBUGF("%p: decrypt - ok", self); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, root); + +ON_FAIL: + PYXMLSEC_DEBUGF("%p: decrypt - fail", self); + Py_XDECREF(node_num); + Py_XDECREF(parent); + return NULL; +} + +static PyGetSetDef PyXmlSec_EncryptionContextGetSet[] = { + { + "key", + (getter)PyXmlSec_EncryptionContextKeyGet, + (setter)PyXmlSec_EncryptionContextKeySet, + (char*)PyXmlSec_EncryptionContextKey__doc__, + NULL + }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef PyXmlSec_EncryptionContextMethods[] = { + { + "encrypt_binary", + (PyCFunction)PyXmlSec_EncryptionContextEncryptBinary, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_EncryptionContextEncryptBinary__doc__, + }, + { + "encrypt_xml", + (PyCFunction)PyXmlSec_EncryptionContextEncryptXml, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_EncryptionContextEncryptXml__doc__ + }, + { + "encrypt_uri", + (PyCFunction)PyXmlSec_EncryptionContextEncryptUri, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_EncryptionContextEncryptUri__doc__ + }, + { + "decrypt", + (PyCFunction)PyXmlSec_EncryptionContextDecrypt, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_EncryptionContextDecrypt__doc__ + }, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject _PyXmlSec_EncryptionContextType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) ".EncryptionContext", /* tp_name */ + sizeof(PyXmlSec_EncryptionContext), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_EncryptionContext__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + "XML Encryption implementation", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyXmlSec_EncryptionContextMethods, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_EncryptionContextGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + PyXmlSec_EncryptionContext__init__, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyXmlSec_EncryptionContext__new__, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_EncryptionContextType = &_PyXmlSec_EncryptionContextType; + +int PyXmlSec_EncModule_Init(PyObject* package) { + if (PyType_Ready(PyXmlSec_EncryptionContextType) < 0) goto ON_FAIL; + + PYXMLSEC_DEBUGF("%p", PyXmlSec_EncryptionContextType); + // since objects is created as static objects, need to increase refcount to prevent deallocate + Py_INCREF(PyXmlSec_EncryptionContextType); + + if (PyModule_AddObject(package, "EncryptionContext", (PyObject*)PyXmlSec_EncryptionContextType) < 0) goto ON_FAIL; + return 0; +ON_FAIL: + return -1; +} diff --git a/src/exception.c b/src/exception.c new file mode 100644 index 00000000..3de0040d --- /dev/null +++ b/src/exception.c @@ -0,0 +1,166 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "exception.h" +#include "utils.h" + +#include +#include + +#include + +// default error class +PyObject* PyXmlSec_Error; +PyObject* PyXmlSec_InternalError; +PyObject* PyXmlSec_VerificationError; + +static int PyXmlSec_LastErrorKey = 0; + +typedef struct { + const xmlChar* file; + const xmlChar* func; + const xmlChar* object; + const xmlChar* subject; + const xmlChar* msg; + int line; + int reason; +} PyXmlSec_ErrorHolder; + +PyXmlSec_ErrorHolder* PyXmlSec_ErrorHolderCreate(const char* file, int line, const char* func, const char* object, const char* subject, int reason, const char* msg) { + PyXmlSec_ErrorHolder* h = (PyXmlSec_ErrorHolder*)xmlMalloc(sizeof(PyXmlSec_ErrorHolder)); + + // file and func is __FILE__ and __FUNCTION__ macro, so it can be stored as is. + h->file = XSTR(file); + h->line = line; + h->func = XSTR(func); + h->reason = reason; + // there is no guarantee that object and subject will not be deallocate after exit from function, + // so make a copy + // xmlCharStrdup returns NULL if arg is NULL + h->object = xmlCharStrdup(object); + h->subject = xmlCharStrdup(subject); + h->msg = xmlCharStrdup(msg); + + PYXMLSEC_DEBUGF("new error %p", h); + return h; +} + +void PyXmlSec_ErrorHolderFree(PyXmlSec_ErrorHolder* h) { + if (h != NULL) { + PYXMLSEC_DEBUGF("free error %p", h); + xmlFree((void*)(h->object)); + xmlFree((void*)(h->subject)); + xmlFree((void*)(h->msg)); + xmlFree((void*)(h)); + } +} + +// saves new error in TLS and returns previous +static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) { + if (PyXmlSec_LastErrorKey == 0) { + PYXMLSEC_DEBUG("WARNING: There is no error key."); + PyXmlSec_ErrorHolderFree(e); + return NULL; + } + + // get_key_value and set_key_value are gil free + PyXmlSec_ErrorHolder* v = (PyXmlSec_ErrorHolder*)PyThread_get_key_value(PyXmlSec_LastErrorKey); + PyThread_delete_key_value(PyXmlSec_LastErrorKey); + int r = PyThread_set_key_value(PyXmlSec_LastErrorKey, (void*)e); + PYXMLSEC_DEBUGF("set_key_value returns %d", r); + return v; +} + +// xmlsec library error callback +static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func, const char* object, const char* subject, int reason, const char* msg) { + // TODO do not allocate error object each time. + PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolderCreate(file, line, func, object, subject, reason, msg))); + + // also call default callback + xmlSecErrorsDefaultCallback(file, line, func, object, subject, reason, msg); +} + +// pops the last error which was occurred in current thread +// the gil should be acquired +static PyObject* PyXmlSec_GetLastError(PyObject* type, const char* msg) { + PyXmlSec_ErrorHolder* h = PyXmlSec_ExchangeLastError(NULL); + if (h == NULL) { + return NULL; + } + + PyObject* exc = PyObject_CallFunction(type, "is", h->reason, msg); + if (exc == NULL) goto ON_FAIL; + + PyXmlSec_SetLongAttr(exc, "code", h->reason); + PyXmlSec_SetStringAttr(exc, "message", msg); + PyXmlSec_SetStringAttr(exc, "details", (const char*)xmlSecErrorsSafeString(h->msg)); + PyXmlSec_SetStringAttr(exc, "file", (const char*)xmlSecErrorsSafeString(h->file)); + PyXmlSec_SetLongAttr(exc, "line", h->line); + PyXmlSec_SetStringAttr(exc, "func", (const char*)xmlSecErrorsSafeString(h->func)); + PyXmlSec_SetStringAttr(exc, "object", (const char*)xmlSecErrorsSafeString(h->object)); + PyXmlSec_SetStringAttr(exc, "subject", (const char*)xmlSecErrorsSafeString(h->subject)); + +ON_FAIL: + PyXmlSec_ErrorHolderFree(h); + return exc; +} + +void PyXmlSec_SetLastError2(PyObject* type, const char* msg) { + PyObject* last = PyXmlSec_GetLastError(type, msg); + if (last == NULL) { + PYXMLSEC_DEBUG("WARNING: no xmlsec error"); + last = PyObject_CallFunction(PyXmlSec_InternalError, "is", (int)-1, msg); + if (last == NULL) { + return; + } + } + PyErr_SetObject(type, last); +} + +void PyXmlSec_SetLastError(const char* msg) { + PyXmlSec_SetLastError2(PyXmlSec_Error, msg); +} + +void PyXmlSec_ClearError(void) { + PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(NULL)); +} + +// initializes errors module +int PyXmlSec_ExceptionsModule_Init(PyObject* package) { + PyXmlSec_Error = NULL; + PyXmlSec_InternalError = NULL; + PyXmlSec_VerificationError = NULL; + + if ((PyXmlSec_Error = PyErr_NewExceptionWithDoc( + STRINGIFY(MODULE_NAME) ".Error", "The common exception class.", PyExc_Exception, 0)) == NULL) goto ON_FAIL; + + if ((PyXmlSec_InternalError = PyErr_NewExceptionWithDoc( + STRINGIFY(MODULE_NAME) ".InternalError", "The internal exception class.", PyXmlSec_Error, 0)) == NULL) goto ON_FAIL; + + if ((PyXmlSec_VerificationError = PyErr_NewExceptionWithDoc( + STRINGIFY(MODULE_NAME) ".VerificationError", "The verification exception class.", PyXmlSec_Error, 0)) == NULL) goto ON_FAIL; + + if (PyModule_AddObject(package, "Error", PyXmlSec_Error) < 0) goto ON_FAIL; + if (PyModule_AddObject(package, "InternalError", PyXmlSec_InternalError) < 0) goto ON_FAIL; + if (PyModule_AddObject(package, "VerificationError", PyXmlSec_VerificationError) < 0) goto ON_FAIL; + + PyXmlSec_LastErrorKey = PyThread_create_key(); + if (PyXmlSec_LastErrorKey != 0) { + xmlSecErrorsSetCallback(&PyXmlSec_ErrorCallback); + } + + return 0; + +ON_FAIL: + Py_XDECREF(PyXmlSec_Error); + Py_XDECREF(PyXmlSec_InternalError); + Py_XDECREF(PyXmlSec_VerificationError); + return -1; +} diff --git a/src/exception.h b/src/exception.h new file mode 100644 index 00000000..a94216c6 --- /dev/null +++ b/src/exception.h @@ -0,0 +1,25 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_EXCEPTIONS_H__ +#define __PYXMLSEC_EXCEPTIONS_H__ + +#include "platform.h" + +extern PyObject* PyXmlSec_Error; +extern PyObject* PyXmlSec_InternalError; +extern PyObject* PyXmlSec_VerificationError; + +void PyXmlSec_SetLastError(const char* msg); + +void PyXmlSec_SetLastError2(PyObject* type, const char* msg); + +void PyXmlSec_ClearError(void); + +#endif //__PYXMLSEC_EXCEPTIONS_H__ diff --git a/src/keys.c b/src/keys.c new file mode 100644 index 00000000..dc88f29f --- /dev/null +++ b/src/keys.c @@ -0,0 +1,695 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "constants.h" +#include "exception.h" +#include "keys.h" +#include "utils.h" + +#include + + +static PyObject* PyXmlSec_Key__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { + PyXmlSec_Key* key = (PyXmlSec_Key*)PyType_GenericNew(type, args, kwargs); + PYXMLSEC_DEBUGF("%p: new key", key); + if (key != NULL) { + key->handle = NULL; + key->is_own = 0; + } + return (PyObject*)(key); +} + +static void PyXmlSec_Key__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p: delete key", self); + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + if (key->is_own) { + PYXMLSEC_DEBUGF("%p: delete handle - %p", self, key->handle); + xmlSecKeyDestroy(key->handle); + } + Py_TYPE(self)->tp_free(self); +} + +static PyXmlSec_Key* PyXmlSec_NewKey1(PyTypeObject* type) { + return (PyXmlSec_Key*)PyObject_CallFunctionObjArgs((PyObject*)type, NULL); +} + +static PyObject* PyXmlSec_Key__copy__(PyObject* self) { + PYXMLSEC_DEBUGF("%p: copy key", self); + + xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; + PyXmlSec_Key* key2 = PyXmlSec_NewKey1(Py_TYPE(self)); + + if (handle == NULL || key2 == NULL) { + PYXMLSEC_DEBUGF("%p: null key", self); + return (PyObject*)key2; + } + + Py_BEGIN_ALLOW_THREADS; + key2->handle = xmlSecKeyDuplicate(handle); + Py_END_ALLOW_THREADS; + + if (key2->handle == NULL) { + PYXMLSEC_DEBUGF("%p: failed to duplicate key", self); + PyXmlSec_SetLastError("cannot duplicate key"); + Py_DECREF(key2); + return NULL; + } + key2->is_own = 1; + return (PyObject*)key2; +} + +static const char PyXmlSec_KeyFromMemory__doc__[] = "Load PKI key from memory.\n"; +static PyObject* PyXmlSec_KeyFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "format", "password", NULL}; + + const char* data = NULL; + Py_ssize_t data_size = 0; + const char* password = NULL; + unsigned int format = 0; + + PyXmlSec_Key* key = NULL; + + PYXMLSEC_DEBUG("load key from memory - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#I|z:from_memory", kwlist, &data, &data_size, &format, &password)) { + goto ON_FAIL; + } + + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + key->handle = xmlSecCryptoAppKeyLoadMemory((const xmlSecByte*)data, (xmlSecSize)data_size, format, password, NULL, NULL); + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot load key"); + goto ON_FAIL; + } + + key->is_own = 1; + + PYXMLSEC_DEBUG("load key from memory - ok"); + + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("load key from memory - fail"); + Py_XDECREF(key); + return NULL; +} + +static const char PyXmlSec_KeyFromFile__doc__[] = "Load PKI key from a file.\n"; +static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "format", "password", NULL}; + + PyObject* file = NULL; + const char* password = NULL; + unsigned int format = 0; + + PyXmlSec_Key* key = NULL; + PyObject* bytes = NULL; + int is_content = 0; + const char* data = NULL; + Py_ssize_t data_size = 0; + + PYXMLSEC_DEBUG("load key from file - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OH|z:from_file", kwlist, &file, &format, &password)) { + goto ON_FAIL; + } + + bytes = PyXmlSec_GetFilePathOrContent(file, &is_content); + if (bytes == NULL) goto ON_FAIL; + + if (is_content == 1) { + data = PyBytes_AsStringAndSize2(bytes, &data_size); + } else { + data = PyBytes_AsString(bytes); + } + + if (data == NULL) goto ON_FAIL; + + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + if (is_content) { + key->handle = xmlSecCryptoAppKeyLoadMemory((const xmlSecByte*)data, (xmlSecSize)data_size, format, password, NULL, NULL); + } else { + key->handle = xmlSecCryptoAppKeyLoad(data, format, password, NULL, NULL); + } + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot read key"); + goto ON_FAIL; + } + + key->is_own = 1; + Py_DECREF(bytes); + + PYXMLSEC_DEBUG("load key from file - ok"); + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("load key from file - fail"); + Py_XDECREF(key); + Py_XDECREF(bytes); + return NULL; +} + +static const char PyXmlSec_KeyGenerate__doc__[] = "Generate key of kind *data* with *size* and *type*.\n"; +static PyObject* PyXmlSec_KeyGenerate(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "size", "type", NULL}; + + PyXmlSec_KeyData* keydata = NULL; + short unsigned int keysize = 0; + unsigned int keytype = 0; + + PyXmlSec_Key* key = NULL; + + PYXMLSEC_DEBUG("generate new key - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!HI:generate", kwlist, PyXmlSec_KeyDataType, &keydata, &keysize, &keytype)) { + goto ON_FAIL; + } + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + key->handle = xmlSecKeyGenerate(keydata->id, keysize, keytype); + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot generate key"); + goto ON_FAIL; + } + key->is_own = 1; + PYXMLSEC_DEBUG("generate new key - ok"); + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("generate new key - fail"); + Py_XDECREF(key); + return NULL; +} + +static const char PyXmlSec_KeyFromBinaryFile__doc__[] = "Loads (symmetric) key of kind *data* from *filename*.\n"; +static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "filename", NULL}; + + PyXmlSec_KeyData* keydata = NULL; + PyObject* filepath = NULL; + + PyXmlSec_Key* key = NULL; + + PYXMLSEC_DEBUG("load symmetric key - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&:from_binary_file", kwlist, + PyXmlSec_KeyDataType, &keydata, PyString_FSConverter, &filepath)) + { + goto ON_FAIL; + } + + const char* filename = PyBytes_AsString(filepath); + if (filename == NULL) goto ON_FAIL; + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + key->handle = xmlSecKeyReadBinaryFile(keydata->id, filename); + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot read key"); + goto ON_FAIL; + } + + key->is_own = 1; + Py_DECREF(filepath); + + PYXMLSEC_DEBUG("load symmetric key - ok"); + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("load symmetric key - fail"); + Py_XDECREF(key); + Py_DECREF(filepath); + return NULL; +} + +static const char PyXmlSec_KeyCertFromMemory__doc__[] = "Load certificate from memory.\n"; +static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "format", NULL}; + + const char* data = NULL; + Py_ssize_t data_size = 0; + unsigned int format = 0; + + PyObject* tmp = NULL; + + PYXMLSEC_DEBUGF("%p: load certificate from memory - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#I:load_cert_from_memory", kwlist, &data, &data_size, &format)) { + goto ON_FAIL; + } + + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + int rv = 0; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecCryptoAppKeyCertLoadMemory(key->handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format); + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("cannot load cert"); + goto ON_FAIL; + } + Py_XDECREF(tmp); + PYXMLSEC_DEBUGF("%p: load certificate from memory - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: load certificate from memory - fail", self); + Py_XDECREF(tmp); + return NULL; +} + +static const char PyXmlSec_KeyCertFromFile__doc__[] = "Load certificate from file.\n"; +static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "format", NULL}; + + PyObject* file = NULL; + unsigned int format = 0; + + PyObject* bytes = NULL; + int is_content = 0; + const char* data = NULL; + Py_ssize_t data_size = 0; + + PYXMLSEC_DEBUGF("%p: load certificate from memory - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OI:load_cert_from_file", kwlist, &file, &format)) { + goto ON_FAIL; + } + bytes = PyXmlSec_GetFilePathOrContent(file, &is_content); + if (bytes == NULL) goto ON_FAIL; + + if (is_content == 1) { + data = PyBytes_AsStringAndSize2(bytes, &data_size); + } else { + data = PyBytes_AsString(bytes); + } + + if (data == NULL) goto ON_FAIL; + + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + int rv = 0; + Py_BEGIN_ALLOW_THREADS; + if (is_content) { + rv = xmlSecCryptoAppKeyCertLoadMemory(key->handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format); + } else { + rv = xmlSecCryptoAppKeyCertLoad(key->handle, data, format); + } + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("cannot load cert"); + goto ON_FAIL; + } + Py_DECREF(bytes); + + PYXMLSEC_DEBUGF("%p: load certificate from file - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: load certificate from file - fail", self); + Py_XDECREF(bytes); + return NULL; +} + +static const char PyXmlSec_KeyName__doc__[] = "the name of *key*.\n"; +static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { + PYXMLSEC_DEBUGF("%p: get name of key", self); + xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; + if (handle == NULL) { + PyErr_SetString(PyExc_ValueError, "key is not ready"); + return NULL; + } + return PyString_FromString((const char*)xmlSecKeyGetName(handle)); +} + +static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { + PYXMLSEC_DEBUGF("%p: set name of key %p", self, value); + + xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; + if (handle == NULL) { + PyErr_SetString(PyExc_ValueError, "key is not ready"); + return -1; + } + + const char* name = PyString_AsString(value); + if (name == NULL) return -1; + + xmlSecKeySetName(handle, XSTR(name)); + return 0; +} + +static PyGetSetDef PyXmlSec_KeyGetSet[] = { + { + "name", + (getter)PyXmlSec_KeyNameGet, + (setter)PyXmlSec_KeyNameSet, + (char*)PyXmlSec_KeyName__doc__, + NULL + }, + {NULL} /* Sentinel */ +}; + +static PyMethodDef PyXmlSec_KeyMethods[] = { + { + "from_memory", + (PyCFunction)PyXmlSec_KeyFromMemory, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyFromMemory__doc__, + }, + { + "from_file", + (PyCFunction)PyXmlSec_KeyFromFile, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyFromFile__doc__ + }, + { + "generate", + (PyCFunction)PyXmlSec_KeyGenerate, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyGenerate__doc__ + }, + { + "from_binary_file", + (PyCFunction)PyXmlSec_KeyFromBinaryFile, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyFromBinaryFile__doc__ + }, + { + "load_cert_from_memory", + (PyCFunction)PyXmlSec_KeyCertFromMemory, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyCertFromMemory__doc__ + }, + { + "load_cert_from_file", + (PyCFunction)PyXmlSec_KeyCertFromFile, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyCertFromFile__doc__ + }, + { + "__copy__", + (PyCFunction)PyXmlSec_Key__copy__, + METH_NOARGS, + "", + }, + { + "__deepcopy__", + (PyCFunction)PyXmlSec_Key__copy__, + METH_NOARGS, + "", + }, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject _PyXmlSec_KeyType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) ".Key", /* tp_name */ + sizeof(PyXmlSec_Key), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_Key__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Key", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyXmlSec_KeyMethods, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_KeyGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyXmlSec_Key__new__, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_KeyType = &_PyXmlSec_KeyType; + +// creates a new key object +PyXmlSec_Key* PyXmlSec_NewKey(void) { + return PyXmlSec_NewKey1(PyXmlSec_KeyType); +} + +/// key manager class + +static PyObject* PyXmlSec_KeysManager__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { + PyXmlSec_KeysManager* mgr = (PyXmlSec_KeysManager*)PyType_GenericNew(type, args, kwargs); + PYXMLSEC_DEBUGF("%p: new manager", mgr); + if (mgr != NULL) { + mgr->handle = NULL; + } + return (PyObject*)(mgr); +} + +static int PyXmlSec_KeysManager__init__(PyObject* self, PyObject* args, PyObject* kwargs) { + PYXMLSEC_DEBUGF("%p: init key manager", self); + xmlSecKeysMngrPtr handle = xmlSecKeysMngrCreate(); + if (handle == NULL) { + PyXmlSec_SetLastError("failed to create xmlsecKeyManger"); + return -1; + } + if (xmlSecCryptoAppDefaultKeysMngrInit(handle) < 0) { + xmlSecKeysMngrDestroy(handle); + PyXmlSec_SetLastError("failed to initialize xmlsecKeyManger"); + return -1; + } + PYXMLSEC_DEBUGF("%p: init key manager - done: %p", self, handle); + ((PyXmlSec_KeysManager*)self)->handle = handle; + return 0; +} + +static void PyXmlSec_KeysManager__del__(PyObject* self) { + PYXMLSEC_DEBUGF("%p: delete KeysManager", self); + PyXmlSec_KeysManager* manager = (PyXmlSec_KeysManager*)self; + if (manager->handle != NULL) { + xmlSecKeysMngrDestroy(manager->handle); + } + Py_TYPE(self)->tp_free(self); +} + +static const char PyXmlSec_KeysManagerAddKey__doc__[] = "Adds a copy of *key*.\n"; +static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "key", NULL}; + + PyXmlSec_Key* key; + + PYXMLSEC_DEBUGF("%p(%p): add key - start", self, ((PyXmlSec_KeysManager*)self)->handle); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:add_key", kwlist, PyXmlSec_KeyType, &key)) { + goto ON_FAIL; + } + + if (key->handle == NULL) { + PyErr_SetString(PyExc_ValueError, "the provided key is invalid"); + goto ON_FAIL; + } + + xmlSecKeyPtr key2; + Py_BEGIN_ALLOW_THREADS + key2 = xmlSecKeyDuplicate(key->handle); + Py_END_ALLOW_THREADS; + + if (key2 == NULL) { + PyXmlSec_SetLastError("cannot make copy of key"); + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecCryptoAppDefaultKeysMngrAdoptKey(((PyXmlSec_KeysManager*)self)->handle, key2); + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("cannot add key"); + xmlSecKeyDestroy(key2); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: add key - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: add key - fail", self); + return NULL; +} + +static const char PyXmlSec_KeysManagerLoadCert__doc__[] = "load certificate from *filename*\n*format* - file format\n*type* - key type.\n"; +static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "filename", "format", "type", NULL}; + + const char* filename = NULL; + unsigned int format = 0; + unsigned int type = 0; + + PYXMLSEC_DEBUGF("%p: load cert - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sII:load_cert", kwlist, &filename, &format, &type)) { + goto ON_FAIL; + } + + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecCryptoAppKeysMngrCertLoad(((PyXmlSec_KeysManager*)self)->handle, filename, format, type); + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("cannot load cert"); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: load cert - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: load cert - fail", self); + return NULL; +} + +static const char PyXmlSec_KeysManagerLoadCertFromMemory__doc__[] = "load certificate from *data*\n*format* - file format\n*type* - key type.\n"; +static PyObject* PyXmlSec_KeysManagerLoadCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "data", "format", "type", NULL}; + + const char* data = NULL; + unsigned int type = 0; + unsigned int format = 0; + Py_ssize_t data_size = 0; + + PYXMLSEC_DEBUGF("%p: load cert from memory - start", self); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#II:load_cert", kwlist, &data, &data_size, &format, &type)) { + goto ON_FAIL; + } + + xmlSecKeysMngrPtr handle = ((PyXmlSec_KeysManager*)self)->handle; + int rv; + Py_BEGIN_ALLOW_THREADS; + rv = xmlSecCryptoAppKeysMngrCertLoadMemory(handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format, type); + Py_END_ALLOW_THREADS; + if (rv < 0) { + PyXmlSec_SetLastError("cannot load cert from memory"); + goto ON_FAIL; + } + PYXMLSEC_DEBUGF("%p: load cert from memory - ok", self); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: load cert from memory - fail", self); + return NULL; +} + +static PyMethodDef PyXmlSec_KeysManagerMethods[] = { + { + "add_key", + (PyCFunction)PyXmlSec_KeysManagerAddKey, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeysManagerAddKey__doc__ + }, + { + "load_cert", + (PyCFunction)PyXmlSec_KeysManagerLoadCert, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeysManagerLoadCert__doc__ + }, + { + "load_cert_from_memory", + (PyCFunction)PyXmlSec_KeysManagerLoadCertFromMemory, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeysManagerLoadCertFromMemory__doc__ + }, + {NULL, NULL} /* sentinel */ +}; + +static PyTypeObject _PyXmlSec_KeysManagerType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) ".KeysManager", /* tp_name */ + sizeof(PyXmlSec_KeysManager), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_KeysManager__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT|Py_TPFLAGS_BASETYPE, /* tp_flags */ + "Keys Manager", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyXmlSec_KeysManagerMethods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + PyXmlSec_KeysManager__init__, /* tp_init */ + PyType_GenericAlloc, /* tp_alloc */ + PyXmlSec_KeysManager__new__, /* tp_new */ + PyObject_Del /* tp_free */ +}; + +PyTypeObject* PyXmlSec_KeysManagerType = &_PyXmlSec_KeysManagerType; + + +int PyXmlSec_KeysManagerConvert(PyObject* o, PyXmlSec_KeysManager** p) { + if (o == Py_None) { + *p = NULL; + return 1; + } + if (!PyObject_IsInstance(o, (PyObject*)PyXmlSec_KeysManagerType)) { + PyErr_SetString(PyExc_TypeError, "KeysManager required"); + return 0; + } + *p = (PyXmlSec_KeysManager*)(o); + Py_INCREF(o); + return 1; +} + +int PyXmlSec_KeyModule_Init(PyObject* package) { + if (PyType_Ready(PyXmlSec_KeyType) < 0) goto ON_FAIL; + if (PyType_Ready(PyXmlSec_KeysManagerType) < 0) goto ON_FAIL; + + // since objects is created as static objects, need to increase refcount to prevent deallocate + Py_INCREF(PyXmlSec_KeyType); + Py_INCREF(PyXmlSec_KeysManagerType); + + if (PyModule_AddObject(package, "Key", (PyObject*)PyXmlSec_KeyType) < 0) goto ON_FAIL; + if (PyModule_AddObject(package, "KeysManager", (PyObject*)PyXmlSec_KeysManagerType) < 0) goto ON_FAIL; + + return 0; +ON_FAIL: + return -1; +} diff --git a/src/keys.h b/src/keys.h new file mode 100644 index 00000000..546f7a10 --- /dev/null +++ b/src/keys.h @@ -0,0 +1,37 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_KEY_H__ +#define __PYXMLSEC_KEY_H__ + +#include "platform.h" + +#include + +typedef struct { + PyObject_HEAD + xmlSecKeyPtr handle; + int is_own; +} PyXmlSec_Key; + +extern PyTypeObject* PyXmlSec_KeyType; + +PyXmlSec_Key* PyXmlSec_NewKey(void); + +typedef struct { + PyObject_HEAD + xmlSecKeysMngrPtr handle; +} PyXmlSec_KeysManager; + +extern PyTypeObject* PyXmlSec_KeysManagerType; + +// converts object `o` to PyXmlSec_KeysManager, None will be converted to NULL, increments ref_count +int PyXmlSec_KeysManagerConvert(PyObject* o, PyXmlSec_KeysManager** p); + +#endif //__PYXMLSEC_KEY_H__ diff --git a/src/lxml.c b/src/lxml.c new file mode 100644 index 00000000..3f48135d --- /dev/null +++ b/src/lxml.c @@ -0,0 +1,38 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "lxml.h" + +#include + +#include +#include +#include + + +int PyXmlSec_InitLxmlModule(void) { + return import_lxml__etree(); +} + +PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr xnode) { + return elementFactory(doc, xnode); +} + + +int PyXmlSec_LxmlElementConverter(PyObject* o, PyXmlSec_LxmlElementPtr* p) { + PyXmlSec_LxmlElementPtr node = rootNodeOrRaise(o); + if (node == NULL) { + return 0; + } + *p = node; + // rootNodeOrRaise - increments ref-count, so need to compensate this. + Py_DECREF(node); + return 1; +} diff --git a/src/lxml.h b/src/lxml.h new file mode 100644 index 00000000..f5838d67 --- /dev/null +++ b/src/lxml.h @@ -0,0 +1,31 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_LXML_H__ +#define __PYXMLSEC_LXML_H__ + +#include "platform.h" + +#include +#include + +#include +#include +#include + +typedef struct LxmlElement* PyXmlSec_LxmlElementPtr; +typedef struct LxmlDocument* PyXmlSec_LxmlDocumentPtr; + +// creates a new element +PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr node); + +// converts o to PyObject, None object is not allowed, does not increment ref_counts +int PyXmlSec_LxmlElementConverter(PyObject* o, PyXmlSec_LxmlElementPtr* p); + +#endif // __PYXMLSEC_LXML_H__ diff --git a/src/main.c b/src/main.c new file mode 100644 index 00000000..26159089 --- /dev/null +++ b/src/main.c @@ -0,0 +1,245 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "platform.h" +#include "exception.h" + +#include +#include +#include + +#define _FREE_NONE 0 +#define _FREE_XMLSEC 1 +#define _FREE_ALL 2 + +static int free_mode = _FREE_NONE; + +static void PyXmlSec_Free(int what) { + PYXMLSEC_DEBUGF("free resources %d", what); + switch (what) { + case _FREE_ALL: + xmlSecCryptoAppShutdown(); + case _FREE_XMLSEC: + xmlSecShutdown(); + } + free_mode = _FREE_NONE; +} + +static int PyXmlSec_Init(void) { + if (xmlSecInit() < 0) { + PyXmlSec_SetLastError("cannot initialize xmlsec library."); + PyXmlSec_Free(_FREE_NONE); + return -1; + } + + if (xmlSecCheckVersion() != 1) { + PyXmlSec_SetLastError("xmlsec library version mismatch."); + PyXmlSec_Free(_FREE_XMLSEC); + return -1; + } + +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + if (xmlSecCryptoDLLoadLibrary(NULL) < 0) { + PyXmlSec_SetLastError("cannot load crypto library for xmlsec."); + PyXmlSec_Free(_FREE_XMLSEC); + return -1; + } +#endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ + + /* Init crypto library */ + if (xmlSecCryptoAppInit(NULL) < 0) { + PyXmlSec_SetLastError("cannot initialize crypto library application."); + PyXmlSec_Free(_FREE_XMLSEC); + return -1; + } + + /* Init xmlsec-crypto library */ + if (xmlSecCryptoInit() < 0) { + PyXmlSec_SetLastError("cannot initialize crypto library."); + PyXmlSec_Free(_FREE_ALL); + return -1; + } + free_mode = _FREE_ALL; + return 0; +} + +static char PyXmlSec_PyInit__doc__[] = +"Initialize the library for general operation.\n" \ +"This is called upon library import and does not need to be called\n" \ +"again (unless @ref _shutdown is called explicitly).\n"; +static PyObject* PyXmlSec_PyInit(PyObject *self) { + if (PyXmlSec_Init() < 0) { + return NULL; + } + Py_RETURN_NONE; +} + +static char PyXmlSec_PyShutdown__doc__[] = +"Shutdown the library and cleanup any leftover resources.\n" \ +"This is called automatically upon interpreter termination and\n" \ +"should not need to be called explicitly."; +static PyObject* PyXmlSec_PyShutdown(PyObject* self) { + PyXmlSec_Free(_FREE_ALL); + Py_RETURN_NONE; +} + +static char PyXmlSec_PyEnableDebugOutput__doc__[] = +"Enables or disables calling LibXML2 callback from the default errors callback.\n"; +static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "enabled", NULL}; + PyObject* enabled = Py_True; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:enable_debug_trace", kwlist, &enabled)) { + return NULL; + } + xmlSecErrorsDefaultCallbackEnableOutput(PyObject_IsTrue(enabled)); + Py_RETURN_NONE; +} + +static PyMethodDef PyXmlSec_MainMethods[] = { + { + "init", + (PyCFunction)PyXmlSec_PyInit, + METH_NOARGS, + PyXmlSec_PyInit__doc__ + }, + { + "shutdown", + (PyCFunction)PyXmlSec_PyShutdown, + METH_NOARGS, + PyXmlSec_PyShutdown__doc__ + }, + { + "enable_debug_trace", + (PyCFunction)PyXmlSec_PyEnableDebugOutput, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_PyEnableDebugOutput__doc__ + }, + {NULL, NULL} /* sentinel */ +}; + +// modules entry points +// loads lxml module +int PyXmlSec_InitLxmlModule(void); +// constants +int PyXmlSec_ConstantsModule_Init(PyObject* package); +// exceptions +int PyXmlSec_ExceptionsModule_Init(PyObject* package); +// keys management +int PyXmlSec_KeyModule_Init(PyObject* package); +// init lxml.tree integration +int PyXmlSec_TreeModule_Init(PyObject* package); +// digital signature management +int PyXmlSec_DSModule_Init(PyObject* package); +// encryption management +int PyXmlSec_EncModule_Init(PyObject* package); +// templates management +int PyXmlSec_TemplateModule_Init(PyObject* package); + +#ifdef PY3K + +static int PyXmlSec_PyClear(PyObject *self) { + PyXmlSec_Free(free_mode); + return 0; +} + +static PyModuleDef PyXmlSecModule = { + PyModuleDef_HEAD_INIT, + STRINGIFY(MODULE_NAME), /* name of module */ + STRINGIFY(MODULE_DOC), /* module documentation, may be NULL */ + -1, /* size of per-interpreter state of the module, + or -1 if the module keeps state in global variables. */ + PyXmlSec_MainMethods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + PyXmlSec_PyClear, /* m_clear */ + NULL, /* m_free */ +}; + +#define PYENTRY_FUNC_NAME JOIN(PyInit_, MODULE_NAME) +#define PY_MOD_RETURN(m) return m +#else // PY3K +#define PYENTRY_FUNC_NAME JOIN(init, MODULE_NAME) +#define PY_MOD_RETURN(m) return + +static void PyXmlSec_PyModuleGuard__del__(PyObject* self) +{ + PyXmlSec_Free(free_mode); + Py_TYPE(self)->tp_free(self); +} + +// we need guard to free resources on module unload +typedef struct { + PyObject_HEAD +} PyXmlSec_PyModuleGuard; + +static PyTypeObject PyXmlSec_PyModuleGuardType = { + PyVarObject_HEAD_INIT(NULL, 0) + STRINGIFY(MODULE_NAME) "__Guard", /* tp_name */ + sizeof(PyXmlSec_PyModuleGuard), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_PyModuleGuard__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + 0, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ +}; +#endif // PY3K + +PyMODINIT_FUNC +PYENTRY_FUNC_NAME(void) +{ + PyObject *module = NULL; +#ifdef PY3K + module = PyModule_Create(&PyXmlSecModule); +#else + module = Py_InitModule3(STRINGIFY(MODULE_NAME), PyXmlSec_MainMethods, STRINGIFY(MODULE_DOC)); +#endif + if (!module) { + PY_MOD_RETURN(NULL); /* this really should never happen */ + } + PYXMLSEC_DEBUGF("%p", module); + + if (PyXmlSec_Init() < 0) goto ON_FAIL; + + if (PyModule_AddStringConstant(module, "__version__", STRINGIFY(MODULE_VERSION)) < 0) goto ON_FAIL; + + if (PyXmlSec_InitLxmlModule() < 0) goto ON_FAIL; + /* Populate final object settings */ + if (PyXmlSec_ConstantsModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_ExceptionsModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_KeyModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_TreeModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_DSModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_EncModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_TemplateModule_Init(module) < 0) goto ON_FAIL; + +#ifndef PY3K + if (PyType_Ready(&PyXmlSec_PyModuleGuardType) < 0) goto ON_FAIL; + PYXMLSEC_DEBUGF("%p", &PyXmlSec_PyModuleGuardType); + // added guard to free resources on module unload, this should be called after last + if (PyModule_AddObject(module, "__guard", _PyObject_New(&PyXmlSec_PyModuleGuardType)) < 0) goto ON_FAIL; +#endif + + PY_MOD_RETURN(module); +ON_FAIL: + Py_DECREF(module); + PY_MOD_RETURN(NULL); +} diff --git a/src/platform.h b/src/platform.h new file mode 100644 index 00000000..bde45cee --- /dev/null +++ b/src/platform.h @@ -0,0 +1,80 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_PLATFORM_H__ +#define __PYXMLSEC_PLATFORM_H__ + +#define PY_SSIZE_T_CLEAN 1 + +#include +#include + +#ifdef MS_WIN32 +#include +#endif /* MS_WIN32 */ + +#define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 8) | (XMLSEC_VERSION_MINOR << 4) | (XMLSEC_VERSION_SUBMINOR)) + +#define XSTR(c) (const xmlChar*)(c) + +#if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) +typedef int Py_ssize_t; +#define PY_SSIZE_T_MAX INT_MAX +#define PY_SSIZE_T_MIN INT_MIN +#endif + +#if PY_MAJOR_VERSION >= 3 +#define PY3K 1 +#define PyString_FromStringAndSize PyUnicode_FromStringAndSize + +#define PyString_FromString PyUnicode_FromString + +#define PyString_AsString PyUnicode_AsUTF8 +#define PyString_AsUtf8AndSize PyUnicode_AsUTF8AndSize + +#define PyCreateDummyObject PyModule_New + +#define PyString_FSConverter PyUnicode_FSConverter +#else // PY3K + +#define PyBytes_Check PyString_Check +#define PyBytes_FromStringAndSize PyString_FromStringAndSize + +#define PyBytes_AsString PyString_AsString +#define PyBytes_AsStringAndSize PyString_AsStringAndSize + +static inline char* PyString_AsUtf8AndSize(PyObject *obj, Py_ssize_t* length) { + char* buffer = NULL; + return (PyString_AsStringAndSize(obj, &buffer, length) < 0) ? (char*)(0) : buffer; +} + +static inline PyObject* PyCreateDummyObject(const char* name) { + PyObject* tmp = Py_InitModule(name, NULL); + Py_INCREF(tmp); + return tmp; +} + +static inline int PyString_FSConverter(PyObject* o, PyObject** p) { + if (o == NULL) { + return 0; + } + + Py_INCREF(o); + *p = o; + return 1; +} + +#endif // PYTHON3 + +static inline char* PyBytes_AsStringAndSize2(PyObject *obj, Py_ssize_t* length) { + char* buffer = NULL; + return ((PyBytes_AsStringAndSize(obj, &buffer, length) < 0) ? (char*)(0) : buffer); +} + +#endif //__PYXMLSEC_PLATFORM_H__ diff --git a/src/template.c b/src/template.c new file mode 100644 index 00000000..cc67b244 --- /dev/null +++ b/src/template.c @@ -0,0 +1,738 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "platform.h" +#include "exception.h" +#include "constants.h" +#include "lxml.h" + +#include + +#define PYXMLSEC_TEMPLATES_DOC "Xml Templates processing" + +static char PyXmlSec_TemplateCreate__doc__[] = \ + "Creates new node with the mandatory , ,\n" + " and children and sub-children.\n"; +static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "c14n_method", "sign_method", "name", "ns", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyXmlSec_Transform* c14n = NULL; + PyXmlSec_Transform* sign = NULL; + const char* name = NULL; + const char* ns = NULL; + + PYXMLSEC_DEBUG("template create - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!O!|zz:create", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &c14n, PyXmlSec_TransformType, &sign, &name, &ns)) + { + goto ON_FAIL; + } + + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplSignatureCreateNsPref(node->_doc->_c_doc, c14n->id, sign->id, XSTR(name), XSTR(ns)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot create template."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template create - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template create - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddReference__doc__[] = \ + "Adds node with given URI (uri ), Id (id ) and Type (type ) attributes and\n" + "the required children and to the child of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "digest_method", "id", "uri", "type", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyXmlSec_Transform* digest = NULL; + const char* id = NULL; + const char* uri = NULL; + const char* type = NULL; + + PYXMLSEC_DEBUG("template add_reference - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzz:add_reference", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &digest, &id, &uri, &type)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplSignatureAddReference(node->_c_node, digest->id, XSTR(id), XSTR(uri), XSTR(type)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add reference."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_reference - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_reference - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddTransform__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "transform", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyXmlSec_Transform* transform = NULL; + + PYXMLSEC_DEBUG("template add_transform - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!:add_transform", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &transform)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplReferenceAddTransform(node->_c_node, transform->id); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add transform."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_transform - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_transform - fail"); + return NULL; +} + +static char PyXmlSec_TemplateEnsureKeyInfo__doc__[] = \ + "Adds (if necessary) node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "id", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* id = NULL; + + PYXMLSEC_DEBUG("template ensure_key_info - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:ensure_key_info", kwlist, PyXmlSec_LxmlElementConverter, &node, &id)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplSignatureEnsureKeyInfo(node->_c_node, XSTR(id)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot ensure key info."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template ensure_key_info - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template ensure_key_info - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddKeyName__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "name", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* name = NULL; + + PYXMLSEC_DEBUG("template add_key_name - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:add_key_name", kwlist, PyXmlSec_LxmlElementConverter, &node, &name)) + { + goto ON_FAIL; + } + + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplKeyInfoAddKeyName(node->_c_node, XSTR(name)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add key name."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_key_name - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_key_name - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddKeyValue__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template add_key_value - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:add_key_value", kwlist, PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplKeyInfoAddKeyValue(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add key value."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_key_name - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_key_name - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509Data__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template add_x509_data - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:add_x509_data", kwlist, PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplKeyInfoAddX509Data(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 data."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_x509_data - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_x509_data - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataAddIssuerSerial__doc__[] = \ + "Adds node to the given node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template x509_data_add_issuer_serial - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_issuer_serial", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509DataAddIssuerSerial(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 issuer serial."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_data_add_issuer_serial - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_data_add_issuer_serial - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "name", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* name = NULL; + + PYXMLSEC_DEBUG("template x509_issuer_serial_add_issuer_name - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:x509_issuer_serial_add_issuer_name", kwlist, + PyXmlSec_LxmlElementConverter, &node, &name)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509IssuerSerialAddIssuerName(node->_c_node, XSTR(name)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 issuer serial name."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_issuer_serial_add_issuer_name - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_issuer_serial_add_issuer_name - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber__doc__[] = \ + "Adds node to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "serial", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* serial = NULL; + + PYXMLSEC_DEBUG("template x509_issuer_serial_add_serial_number - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:x509_issuer_serial_add_serial_number", kwlist, + PyXmlSec_LxmlElementConverter, &node, &serial)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509IssuerSerialAddSerialNumber(node->_c_node, XSTR(serial)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 issuer serial number."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_issuer_serial_add_serial_number - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_issuer_serial_add_serial_number - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataAddSubjectName__doc__[] = \ + "Adds node to the given node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template x509_data_add_subject_name - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_subject_name", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509DataAddSubjectName(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 subject name."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_data_add_subject_name - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_data_add_subject_name - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataAddSKI__doc__[] = \ + "Adds node to the given node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template x509_data_add_ski - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_ski", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509DataAddSKI(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 SKI."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_data_add_ski - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_data_add_ski - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataAddCertificate__doc__[] = \ + "Adds node to the given node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template x509_data_add_certificate - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_certificate", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509DataAddCertificate(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 certificate."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_data_add_certificate - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_data_add_certificate - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddX509DataAddCRL__doc__[] = \ + "Adds node to the given node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template x509_data_add_crl - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_crl", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplX509DataAddCRL(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add x509 CRL."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template x509_data_add_crl - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template x509_data_add_crl - fail"); + return NULL; +} + +static char PyXmlSec_TemplateAddEncryptedKey__doc__[] = \ + "Adds node with given attributes to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "method", "id", "type", "recipient", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyXmlSec_Transform* method = NULL; + const char* id = NULL; + const char* type = NULL; + const char* recipient = NULL; + + PYXMLSEC_DEBUG("template add_encrypted_key - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzz:add_encrypted_key", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &method, &id, &type, &recipient)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplKeyInfoAddEncryptedKey(node->_c_node, method->id, XSTR(id), XSTR(type), XSTR(recipient)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot add encrypted key."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template add_encrypted_key - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template add_encrypted_key - fail"); + return NULL; +} + +static char PyXmlSec_TemplateCreateEncryptedData__doc__[] = \ + "Creates new <{ns}:EncryptedData /> node for encryption template.\n"; +static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "method", "id", "type", "mime_type", "encoding", "ns", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyXmlSec_Transform* method = NULL; + const char* id = NULL; + const char* type = NULL; + const char* mime_type = NULL; + const char* encoding = NULL; + const char* ns = NULL; + + PYXMLSEC_DEBUG("template encrypted_data_create - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzzzz:encrypted_data_create", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &method, &id, &type, &mime_type, &encoding, &ns)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplEncDataCreate(node->_doc->_c_doc, method->id, XSTR(id), XSTR(type), XSTR(mime_type), XSTR(encoding)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot create encrypted data."); + goto ON_FAIL; + } + if (ns != NULL) { + res->ns->prefix = xmlStrdup(XSTR(ns)); + } + + PYXMLSEC_DEBUG("template encrypted_data_create - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template encrypted_data_create - fail"); + return NULL; +} + +static char PyXmlSec_TemplateEncryptedDataEnsureKeyInfo__doc__[] = \ + "Adds <{ns}:KeyInfo/> to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "id", "ns", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* id = NULL; + const char* ns = NULL; + + PYXMLSEC_DEBUG("template encrypted_data_ensure_key_info - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|zz:encrypted_data_ensure_key_info", kwlist, + PyXmlSec_LxmlElementConverter, &node, &id, &ns)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplEncDataEnsureKeyInfo(node->_c_node, XSTR(id)); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot ensure key info for encrypted data."); + goto ON_FAIL; + } + if (ns != NULL) { + res->ns->prefix = xmlStrdup(XSTR(ns)); + } + + PYXMLSEC_DEBUG("template encrypted_data_ensure_key_info - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template encrypted_data_ensure_key_info - fail"); + return NULL; +} + +static char PyXmlSec_TemplateEncryptedDataEnsureCipherValue__doc__[] = \ + "Adds to the node of *node*.\n"; +static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + + PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:encrypted_data_ensure_cipher_value", kwlist, + PyXmlSec_LxmlElementConverter, &node)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplEncDataEnsureCipherValue(node->_c_node); + Py_END_ALLOW_THREADS; + if (res == NULL) { + PyXmlSec_SetLastError("cannot ensure cipher value for encrypted data."); + goto ON_FAIL; + } + + PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - ok"); + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - fail"); + return NULL; +} + + +static PyMethodDef PyXmlSec_TemplateMethods[] = { + { + "create", + (PyCFunction)PyXmlSec_TemplateCreate, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateCreate__doc__ + }, + { + "add_reference", + (PyCFunction)PyXmlSec_TemplateAddReference, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddReference__doc__ + }, + { + "add_transform", + (PyCFunction)PyXmlSec_TemplateAddTransform, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddTransform__doc__ + }, + { + "ensure_key_info", + (PyCFunction)PyXmlSec_TemplateEnsureKeyInfo, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateEnsureKeyInfo__doc__ + }, + { + "add_key_name", + (PyCFunction)PyXmlSec_TemplateAddKeyName, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddKeyName__doc__ + }, + { + "add_key_value", + (PyCFunction)PyXmlSec_TemplateAddKeyValue, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddKeyValue__doc__ + }, + { + "add_x509_data", + (PyCFunction)PyXmlSec_TemplateAddX509Data, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509Data__doc__ + }, + { + "x509_data_add_issuer_serial", + (PyCFunction)PyXmlSec_TemplateAddX509DataAddIssuerSerial, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataAddIssuerSerial__doc__ + }, + { + "x509_issuer_serial_add_issuer_name", + (PyCFunction)PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName__doc__ + }, + { + "x509_issuer_serial_add_serial_number", + (PyCFunction)PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber__doc__ + }, + { + "x509_data_add_subject_name", + (PyCFunction)PyXmlSec_TemplateAddX509DataAddSubjectName, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataAddSubjectName__doc__ + }, + { + "x509_data_add_ski", + (PyCFunction)PyXmlSec_TemplateAddX509DataAddSKI, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataAddSKI__doc__ + }, + { + "x509_data_add_certificate", + (PyCFunction)PyXmlSec_TemplateAddX509DataAddCertificate, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataAddCertificate__doc__ + }, + { + "x509_data_add_crl", + (PyCFunction)PyXmlSec_TemplateAddX509DataAddCRL, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddX509DataAddCRL__doc__ + }, + { + "add_encrypted_key", + (PyCFunction)PyXmlSec_TemplateAddEncryptedKey, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateAddEncryptedKey__doc__ + }, + { + "encrypted_data_create", + (PyCFunction)PyXmlSec_TemplateCreateEncryptedData, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateCreateEncryptedData__doc__ + }, + { + "encrypted_data_ensure_key_info", + (PyCFunction)PyXmlSec_TemplateEncryptedDataEnsureKeyInfo, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateEncryptedDataEnsureKeyInfo__doc__ + }, + { + "encrypted_data_ensure_cipher_value", + (PyCFunction)PyXmlSec_TemplateEncryptedDataEnsureCipherValue, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateEncryptedDataEnsureCipherValue__doc__ + }, + {NULL, NULL} /* sentinel */ +}; + +#ifdef PY3K +static PyModuleDef PyXmlSec_TemplateModule = +{ + PyModuleDef_HEAD_INIT, + STRINGIFY(MODULE_NAME) ".template", + PYXMLSEC_TEMPLATES_DOC, + -1, + PyXmlSec_TemplateMethods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif // PY3K + +int PyXmlSec_TemplateModule_Init(PyObject* package) { +#ifdef PY3K + PyObject* template = PyModule_Create(&PyXmlSec_TemplateModule); +#else + PyObject* template = Py_InitModule3(STRINGIFY(MODULE_NAME) ".template", PyXmlSec_TemplateMethods, PYXMLSEC_TEMPLATES_DOC); + Py_XINCREF(template); +#endif + + if (!template) goto ON_FAIL; + PYXMLSEC_DEBUGF("%p", template); + + if (PyModule_AddObject(package, "template", template) < 0) goto ON_FAIL; + + return 0; +ON_FAIL: + Py_XDECREF(template); + return -1; +} diff --git a/src/tree.c b/src/tree.c new file mode 100644 index 00000000..b2fc4ddc --- /dev/null +++ b/src/tree.c @@ -0,0 +1,228 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "common.h" +#include "utils.h" +#include "lxml.h" + +#include + +#define PYXMLSEC_TREE_DOC "Common XML utility functions" + +static char PyXmlSec_TreeFindChild__doc__[] = \ + "Searches a direct child of the parent node having given name and namespace href.\n"; +static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "parent", "name", "namespace", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* name = NULL; + const char* ns = (const char*)xmlSecDSigNs; + + PYXMLSEC_DEBUG("tree find_child - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_child", kwlist, + PyXmlSec_LxmlElementConverter, &node, &name, &ns)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecFindChild(node->_c_node, XSTR(name), XSTR(ns)); + Py_END_ALLOW_THREADS; + + PYXMLSEC_DEBUG("tree find_child - ok"); + if (res == NULL) { + Py_RETURN_NONE; + } + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("tree find_child - fail"); + return NULL; +} + +static char PyXmlSec_TreeFindParent__doc__[] = \ + "Searches the ancestors axis of the node having given name and namespace href.\n"; +static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "name", "namespace", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* name = NULL; + const char* ns = (const char*)xmlSecDSigNs; + + PYXMLSEC_DEBUG("tree find_parent - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_parent", kwlist, + PyXmlSec_LxmlElementConverter, &node, &name, &ns)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecFindParent(node->_c_node, XSTR(name), XSTR(ns)); + Py_END_ALLOW_THREADS; + + PYXMLSEC_DEBUG("tree find_parent - ok"); + if (res == NULL) { + Py_RETURN_NONE; + } + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("tree find_parent - fail"); + return NULL; +} + +static char PyXmlSec_TreeFindNode__doc__[] = \ + "Searches all children of the parent node having given name and namespace href.\n"; +static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "name", "namespace", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + const char* name = NULL; + const char* ns = (const char*)xmlSecDSigNs; + + PYXMLSEC_DEBUG("tree find_node - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_node", kwlist, + PyXmlSec_LxmlElementConverter, &node, &name, &ns)) + { + goto ON_FAIL; + } + xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; + res = xmlSecFindNode(node->_c_node, XSTR(name), XSTR(ns)); + Py_END_ALLOW_THREADS; + + PYXMLSEC_DEBUG("tree find_node - ok"); + if (res == NULL) { + Py_RETURN_NONE; + } + return (PyObject*)PyXmlSec_elementFactory(node->_doc, res); + +ON_FAIL: + PYXMLSEC_DEBUG("tree find_node - fail"); + return NULL; +} + +static char PyXmlSec_TreeAddIds__doc__[] = \ + "Registers *ids* as ids used below *node*. *ids* is a sequence of attribute names\n"\ + "used as XML ids in the subtree rooted at *node*.\n"\ + "A call to `addIds` may be necessary to make known which attributes contain XML ids.\n"\ + "This is the case, if a transform references an id via `XPointer` or a self document uri and\n" + "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n"; +static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "ids", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyObject* ids = NULL; + + const xmlChar** list = NULL; + + PYXMLSEC_DEBUG("tree add_ids - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O:add_ids", kwlist, PyXmlSec_LxmlElementConverter, &node, &ids)) + { + goto ON_FAIL; + } + Py_ssize_t n = PyObject_Length(ids); + if (n < 0) goto ON_FAIL; + + list = (const xmlChar**)xmlMalloc(sizeof(xmlChar*) * (n + 1)); + if (list == NULL) { + PyErr_SetString(PyExc_MemoryError, "no memory"); + goto ON_FAIL; + } + + PyObject* tmp; + PyObject* key; + for (Py_ssize_t i = 0; i < n; ++i) { + key = PyLong_FromSsize_t(i); + if (key == NULL) goto ON_FAIL; + tmp = PyObject_GetItem(ids, key); + Py_DECREF(key); + if (tmp == NULL) goto ON_FAIL; + list[i] = XSTR(PyString_AsString(tmp)); + Py_DECREF(tmp); + if (list[i] == NULL) goto ON_FAIL; + } + list[n] = NULL; + + Py_BEGIN_ALLOW_THREADS; + xmlSecAddIDs(node->_doc->_c_doc, node->_c_node, list); + Py_END_ALLOW_THREADS; + + PyMem_Free(list); + + PYXMLSEC_DEBUG("tree add_ids - ok"); + Py_RETURN_NONE; +ON_FAIL: + PYXMLSEC_DEBUG("tree add_ids - fail"); + xmlFree(list); + return NULL; +} + +static PyMethodDef PyXmlSec_TreeMethods[] = { + { + "find_child", + (PyCFunction)PyXmlSec_TreeFindChild, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TreeFindChild__doc__, + }, + { + "find_parent", + (PyCFunction)PyXmlSec_TreeFindParent, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TreeFindParent__doc__, + }, + { + "find_node", + (PyCFunction)PyXmlSec_TreeFindNode, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TreeFindNode__doc__, + }, + { + "add_ids", + (PyCFunction)PyXmlSec_TreeAddIds, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TreeAddIds__doc__, + }, + {NULL, NULL} /* sentinel */ +}; + +#ifdef PY3K +static PyModuleDef PyXmlSec_TreeModule = +{ + PyModuleDef_HEAD_INIT, + STRINGIFY(MODULE_NAME) ".tree", + PYXMLSEC_TREE_DOC, + -1, + PyXmlSec_TreeMethods, /* m_methods */ + NULL, /* m_slots */ + NULL, /* m_traverse */ + NULL, /* m_clear */ + NULL, /* m_free */ +}; +#endif // PY3K + + +int PyXmlSec_TreeModule_Init(PyObject* package) { +#ifdef PY3K + PyObject* tree = PyModule_Create(&PyXmlSec_TreeModule); +#else + PyObject* tree = Py_InitModule3(STRINGIFY(MODULE_NAME) ".template", PyXmlSec_TreeMethods, PYXMLSEC_TREE_DOC); + Py_XINCREF(tree); +#endif + + if (!tree) goto ON_FAIL; + + PYXMLSEC_DEBUGF("%", tree); + if (PyModule_AddObject(package, "tree", tree) < 0) goto ON_FAIL; + + return 0; +ON_FAIL: + Py_XDECREF(tree); + return -1; +} diff --git a/src/utils.c b/src/utils.c new file mode 100644 index 00000000..679a1b2d --- /dev/null +++ b/src/utils.c @@ -0,0 +1,49 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#include "utils.h" + +PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { + if (PyObject_HasAttrString(file, "read")) { + PyObject* data = PyObject_CallMethod(file, "read", NULL); + if (data != NULL && PyUnicode_Check(data)) { + PyObject* utf8 = PyUnicode_AsUTF8String(data); + Py_DECREF(data); + data = utf8; + } + *is_content = 1; + return data; + } + *is_content = 0; + PyObject* tmp = NULL; + if (!PyString_FSConverter(file, &tmp)) { + return NULL; + } + return tmp; +} + +int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value) { + PyObject* tmp = PyString_FromString(value); + if (tmp == NULL) { + return -1; + } + int r = PyObject_SetAttrString(obj, name, tmp); + Py_DECREF(tmp); + return r; +} + +int PyXmlSec_SetLongAttr(PyObject* obj, const char* name, long value) { + PyObject* tmp = PyLong_FromLong(value); + if (tmp == NULL) { + return -1; + } + int r = PyObject_SetAttrString(obj, name, tmp); + Py_DECREF(tmp); + return r; +} diff --git a/src/utils.h b/src/utils.h new file mode 100644 index 00000000..a250ccbc --- /dev/null +++ b/src/utils.h @@ -0,0 +1,22 @@ +// Copyright (c) 2017 Ryan Leckey +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +// SOFTWARE. + +#ifndef __PYXMLSEC_UTILS_H__ +#define __PYXMLSEC_UTILS_H__ + +#include "platform.h" + +int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value); + +int PyXmlSec_SetLongAttr(PyObject* obj, const char* name, long value); + +// return content if file is fileobject, or fs encoded filepath +PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content); + +#endif //__PYXMLSEC_UTILS_H__ diff --git a/src/xmlsec.h b/src/xmlsec.h deleted file mode 100644 index ac0f3e75..00000000 --- a/src/xmlsec.h +++ /dev/null @@ -1,9 +0,0 @@ -#include -#include -#include -#include -#include -#include -#include -#include -#include diff --git a/src/xmlsec/__init__.py b/src/xmlsec/__init__.py deleted file mode 100644 index 106b1f00..00000000 --- a/src/xmlsec/__init__.py +++ /dev/null @@ -1,18 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division -import atexit -from .meta import version as __version__, description as __doc__ -from .constants import * -from .utils import * -from .key import * -from .ds import * -from .enc import * -from .error import * -from . import tree, template - - -if not init(): - raise RuntimeError('Failed to initialize the xmlsec library.') - - -atexit.register(shutdown) diff --git a/src/xmlsec/constants.pxd b/src/xmlsec/constants.pxd deleted file mode 100644 index 40a3d2b8..00000000 --- a/src/xmlsec/constants.pxd +++ /dev/null @@ -1,118 +0,0 @@ -from lxml.includes.tree cimport const_xmlChar - - -cdef extern from "xmlsec.h": # xmlsec/strings.h - # Global namespaces. - const_xmlChar* xmlSecNs - const_xmlChar* xmlSecDSigNs - const_xmlChar* xmlSecEncNs - const_xmlChar* xmlSecXPathNs - const_xmlChar* xmlSecXPath2Ns - const_xmlChar* xmlSecXPointerNs - const_xmlChar* xmlSecSoap11Ns - const_xmlChar* xmlSecSoap12Ns - - # Digital signature nodes. - const_xmlChar* xmlSecNodeSignature - const_xmlChar* xmlSecNodeSignedInfo - const_xmlChar* xmlSecNodeCanonicalizationMethod - const_xmlChar* xmlSecNodeSignatureMethod - const_xmlChar* xmlSecNodeSignatureValue - const_xmlChar* xmlSecNodeDigestMethod - const_xmlChar* xmlSecNodeDigestValue - const_xmlChar* xmlSecNodeObject - const_xmlChar* xmlSecNodeManifest - const_xmlChar* xmlSecNodeSignatureProperties - - # Encypted nodes - const_xmlChar* xmlSecNodeEncryptedData - const_xmlChar* xmlSecNodeEncryptedKey - const_xmlChar* xmlSecNodeEncryptionMethod - const_xmlChar* xmlSecNodeEncryptionProperties - const_xmlChar* xmlSecNodeEncryptionProperty - const_xmlChar* xmlSecNodeCipherData - const_xmlChar* xmlSecNodeCipherValue - const_xmlChar* xmlSecNodeCipherReference - const_xmlChar* xmlSecNodeReferenceList - const_xmlChar* xmlSecNodeDataReference - const_xmlChar* xmlSecNodeKeyReference - const_xmlChar* xmlSecNodeKeyInfo - - - # encryption types - const_xmlChar* xmlSecTypeEncContent - const_xmlChar* xmlSecTypeEncElement - - ctypedef unsigned int xmlSecTransformUsage - cdef enum: - xmlSecTransformUsageUnknown=0x0000 - xmlSecTransformUsageDSigTransform=0x0001 - xmlSecTransformUsageC14NMethod=0x0002 - xmlSecTransformUsageDigestMethod=0x0004 - xmlSecTransformUsageSignatureMethod=0x0008 - xmlSecTransformUsageEncryptionMethod=0x0010 - xmlSecTransformUsageAny=0xFFFF - - # Transform ids # xmlsec/app.h - cdef struct _xmlSecTransformKlass: - const_xmlChar* name - const_xmlChar* href - xmlSecTransformUsage usage - - ctypedef _xmlSecTransformKlass *xmlSecTransformId - - xmlSecTransformId xmlSecTransformInclC14NGetKlass() nogil - xmlSecTransformId xmlSecTransformInclC14NWithCommentsGetKlass() nogil - xmlSecTransformId xmlSecTransformInclC14N11GetKlass() nogil - xmlSecTransformId xmlSecTransformInclC14N11WithCommentsGetKlass() nogil - xmlSecTransformId xmlSecTransformExclC14NGetKlass() nogil - xmlSecTransformId xmlSecTransformExclC14NWithCommentsGetKlass() nogil - xmlSecTransformId xmlSecTransformEnvelopedGetKlass() nogil - xmlSecTransformId xmlSecTransformXPathGetKlass() nogil - xmlSecTransformId xmlSecTransformXPath2GetKlass() nogil - xmlSecTransformId xmlSecTransformXPointerGetKlass() nogil - xmlSecTransformId xmlSecTransformXsltGetKlass() nogil - xmlSecTransformId xmlSecTransformRemoveXmlTagsC14NGetKlass() nogil - xmlSecTransformId xmlSecTransformVisa3DHackGetKlass() nogil - - xmlSecTransformId xmlSecOpenSSLTransformAes128CbcGetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformAes192CbcGetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformAes256CbcGetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformKWAes128GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformKWAes192GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformKWAes256GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformDes3CbcGetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformKWDes3GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformDsaSha1GetKlass() nogil - # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha1GetKlass() nogil - # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha224GetKlass() nogil - # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha256GetKlass() nogil - # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha384GetKlass() nogil - # xmlSecTransformId xmlSecOpenSSLTransformEcdsaSha512GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacMd5GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacRipemd160GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacSha1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacSha224GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacSha256GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacSha384GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformHmacSha512GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformMd5GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRipemd160GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaMd5GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaRipemd160GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaSha1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaSha224GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaSha256GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaSha384GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaSha512GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaPkcs1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformRsaOaepGetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformSha1GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformSha224GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformSha256GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformSha384GetKlass() nogil - xmlSecTransformId xmlSecOpenSSLTransformSha512GetKlass() nogil - - -cdef class _Transform(object): - cdef xmlSecTransformId target diff --git a/src/xmlsec/constants.pyx b/src/xmlsec/constants.pyx deleted file mode 100644 index a6de7cd8..00000000 --- a/src/xmlsec/constants.pyx +++ /dev/null @@ -1,131 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from .constants cimport * -from .utils cimport _u - -__all__ = [ - 'Namespace', - 'Node', - 'Transform', - 'EncryptionType' -] - - -class Namespace: - """Global namespaces.""" - BASE = _u(xmlSecNs) - DS = _u(xmlSecDSigNs) - ENC = _u(xmlSecEncNs) - XPATH = _u(xmlSecXPathNs) - XPATH2 = _u(xmlSecXPath2Ns) - XPOINTER = _u(xmlSecXPointerNs) - SOAP11 = _u(xmlSecSoap11Ns) - SOAP12 = _u(xmlSecSoap12Ns) - - -class EncryptionType: - CONTENT = _u(xmlSecTypeEncContent) - ELEMENT = _u(xmlSecTypeEncElement) - - -class Node: - """Digital signature nodes.""" - SIGNATURE = _u(xmlSecNodeSignature) - SIGNED_INFO = _u(xmlSecNodeSignedInfo) - CANONICALIZATION_METHOD = _u(xmlSecNodeCanonicalizationMethod) - SIGNATURE_METHOD = _u(xmlSecNodeSignatureMethod) - SIGNATURE_VALUE = _u(xmlSecNodeSignatureValue) - DIGEST_METHOD = _u(xmlSecNodeDigestMethod) - DIGEST_VALUE = _u(xmlSecNodeDigestValue) - OBJECT = _u(xmlSecNodeObject) - MANIFEST = _u(xmlSecNodeManifest) - SIGNATURE_PROPERTIES = _u(xmlSecNodeSignatureProperties) - ENCRYPTED_DATA = _u(xmlSecNodeEncryptedData) - ENCRYPTED_KEY = _u(xmlSecNodeEncryptedKey) - ENCRYPTION_METHOD = _u(xmlSecNodeEncryptionMethod) - ENCRYPTION_PROPERTIES = _u(xmlSecNodeEncryptionProperties) - ENCRYPTION_PROPERTY = _u(xmlSecNodeEncryptionProperty) - CIPHER_DATA = _u(xmlSecNodeCipherData) - CIPHER_VALUE = _u(xmlSecNodeCipherValue) - CIPHER_REFERENCE = _u(xmlSecNodeCipherReference) - REFERENCE_LIST = _u(xmlSecNodeReferenceList) - DATA_REFERENCE = _u(xmlSecNodeDataReference) - KEY_REFERENCE = _u(xmlSecNodeKeyReference) - KEY_INFO = _u(xmlSecNodeKeyInfo) - - -cdef class _Transform: - property name: - def __get__(self): - return _u(self.target.name) - - property href: - def __get__(self): - return _u(self.target.href) - - property usage: - def __get__(self): - return self.target.usage - - -cdef _Transform _mkti(xmlSecTransformId target): - cdef _Transform r = _Transform.__new__(_Transform) - r.target = target - return r - - -class Transform: - """Transform identifiers.""" - - C14N = _mkti(xmlSecTransformInclC14NGetKlass()) - C14N_COMMENTS = _mkti(xmlSecTransformInclC14NWithCommentsGetKlass()) - C14N11 = _mkti(xmlSecTransformInclC14N11GetKlass()) - C14N11_COMMENTS = _mkti(xmlSecTransformInclC14N11WithCommentsGetKlass()) - EXCL_C14N = _mkti(xmlSecTransformExclC14NGetKlass()) - EXCL_C14N_COMMENTS = _mkti(xmlSecTransformExclC14NWithCommentsGetKlass()) - ENVELOPED = _mkti(xmlSecTransformEnvelopedGetKlass()) - XPATH = _mkti(xmlSecTransformXPathGetKlass()) - XPATH2 = _mkti(xmlSecTransformXPath2GetKlass()) - XPOINTER = _mkti(xmlSecTransformXPointerGetKlass()) - XSLT = _mkti(xmlSecTransformXsltGetKlass()) - REMOVE_XML_TAGS_C14N = _mkti(xmlSecTransformRemoveXmlTagsC14NGetKlass()) - VISA3D_HACK = _mkti(xmlSecTransformVisa3DHackGetKlass()) - - AES128 = _mkti(xmlSecOpenSSLTransformAes128CbcGetKlass()) - AES192 = _mkti(xmlSecOpenSSLTransformAes192CbcGetKlass()) - AES256 = _mkti(xmlSecOpenSSLTransformAes256CbcGetKlass()) - KW_AES128 = _mkti(xmlSecOpenSSLTransformKWAes128GetKlass()) - KW_AES192 = _mkti(xmlSecOpenSSLTransformKWAes192GetKlass()) - KW_AES256 = _mkti(xmlSecOpenSSLTransformKWAes256GetKlass()) - DES3 = _mkti(xmlSecOpenSSLTransformDes3CbcGetKlass()) - KW_DES3 = _mkti(xmlSecOpenSSLTransformKWDes3GetKlass()) - DSA_SHA1 = _mkti(xmlSecOpenSSLTransformDsaSha1GetKlass()) - # ECDSA_SHA1 = _mkti(xmlSecOpenSSLTransformEcdsaSha1GetKlass()) - # ECDSA_SHA224 = _mkti(xmlSecOpenSSLTransformEcdsaSha224GetKlass()) - # ECDSA_SHA256 = _mkti(xmlSecOpenSSLTransformEcdsaSha256GetKlass()) - # ECDSA_SHA384 = _mkti(xmlSecOpenSSLTransformEcdsaSha384GetKlass()) - # ECDSA_SHA512 = _mkti(xmlSecOpenSSLTransformEcdsaSha512GetKlass()) - HMAC_MD5 = _mkti(xmlSecOpenSSLTransformHmacMd5GetKlass()) - HMAC_RIPEMD160 = _mkti(xmlSecOpenSSLTransformHmacRipemd160GetKlass()) - HMAC_SHA1 = _mkti(xmlSecOpenSSLTransformHmacSha1GetKlass()) - HMAC_SHA224 = _mkti(xmlSecOpenSSLTransformHmacSha224GetKlass()) - HMAC_SHA256 = _mkti(xmlSecOpenSSLTransformHmacSha256GetKlass()) - HMAC_SHA384 = _mkti(xmlSecOpenSSLTransformHmacSha384GetKlass()) - HMAC_SHA512 = _mkti(xmlSecOpenSSLTransformHmacSha512GetKlass()) - MD5 = _mkti(xmlSecOpenSSLTransformMd5GetKlass()) - RIPEMD160 = _mkti(xmlSecOpenSSLTransformRipemd160GetKlass()) - RSA_MD5 = _mkti(xmlSecOpenSSLTransformRsaMd5GetKlass()) - RSA_RIPEMD160 = _mkti(xmlSecOpenSSLTransformRsaRipemd160GetKlass()) - RSA_SHA1 = _mkti(xmlSecOpenSSLTransformRsaSha1GetKlass()) - RSA_SHA224 = _mkti(xmlSecOpenSSLTransformRsaSha224GetKlass()) - RSA_SHA256 = _mkti(xmlSecOpenSSLTransformRsaSha256GetKlass()) - RSA_SHA384 = _mkti(xmlSecOpenSSLTransformRsaSha384GetKlass()) - RSA_SHA512 = _mkti(xmlSecOpenSSLTransformRsaSha512GetKlass()) - RSA_PKCS1 = _mkti(xmlSecOpenSSLTransformRsaPkcs1GetKlass()) - RSA_OAEP = _mkti(xmlSecOpenSSLTransformRsaOaepGetKlass()) - SHA1 = _mkti(xmlSecOpenSSLTransformSha1GetKlass()) - SHA224 = _mkti(xmlSecOpenSSLTransformSha224GetKlass()) - SHA256 = _mkti(xmlSecOpenSSLTransformSha256GetKlass()) - SHA384 = _mkti(xmlSecOpenSSLTransformSha384GetKlass()) - SHA512 = _mkti(xmlSecOpenSSLTransformSha512GetKlass()) diff --git a/src/xmlsec/ds.pxd b/src/xmlsec/ds.pxd deleted file mode 100644 index e8096677..00000000 --- a/src/xmlsec/ds.pxd +++ /dev/null @@ -1,125 +0,0 @@ -from lxml.includes.tree cimport xmlNode -from lxml.includes.tree cimport const_xmlChar, xmlNode, xmlID, xmlDoc, xmlAttr -from lxml.includes.dtdvalid cimport xmlValidCtxt -from .key cimport xmlSecKeyPtr, xmlSecKeyReq, xmlSecKeyReqPtr, xmlSecKeysMngrPtr -from .constants cimport xmlSecTransformId - - -cdef extern from "xmlsec.h": # xmlsec/keys.h - - ctypedef unsigned int xmlSecSize - ctypedef unsigned char xmlSecByte - ctypedef xmlSecByte const_xmlSecByte "const xmlSecByte" - - ctypedef void * xmlSecPtrList - ctypedef xmlSecPtrList * xmlSecPtrListPtr - ctypedef void * xmlSecPtr - - int xmlSecPtrListAdd(xmlSecPtrListPtr, xmlSecPtr) nogil - - int xmlSecPtrListEmpty(xmlSecPtrListPtr) nogil - - cdef struct _xmlSecBuffer: - xmlSecByte* data - size_t size - # size_t maxSize - # xmlSecAllocMode allocMode - - ctypedef _xmlSecBuffer *xmlSecBufferPtr - - # transforms and transform contexts (partial) - ctypedef enum xmlSecTransformStatus: - xmlSecTransformStatusNone = 0 - xmlSecTransformStatusWorking - xmlSecTransformStatusFinished - xmlSecTransformStatusOk - xmlSecTransformStatusFail - - ctypedef enum xmlSecTransformOperation: - xmlSecTransformOperationNone = 0 - xmlSecTransformOperationEncode - xmlSecTransformOperationDecode - xmlSecTransformOperationSign - xmlSecTransformOperationVerify - xmlSecTransformOperationEncrypt - xmlSecTransformOperationDecrypt - - cdef struct _xmlSecTransform: - xmlSecTransformOperation operation - xmlSecTransformStatus status - - ctypedef _xmlSecTransform* xmlSecTransformPtr - - cdef struct _xmlSecTransformCtx: - xmlSecBufferPtr result - xmlSecTransformStatus status - - ctypedef _xmlSecTransformCtx xmlSecTransformCtx - ctypedef _xmlSecTransformCtx* xmlSecTransformCtxPtr - - cdef struct xmlSecKeyInfoCtx: - xmlSecPtrList enabledKeyData - xmlSecKeyReq keyReq - - ctypedef enum xmlSecDSigStatus: - xmlSecDSigStatusUnknown = 0 - xmlSecDSigStatusSucceeded = 1 - xmlSecDSigStatusInvalid = 2 - - cdef struct _xmlSecDSigCtx: - # void* userData - # unsigned int flags - # unsigned int flags2 - xmlSecKeyInfoCtx keyInfoReadCtx - # xmlSecKeyInfoCtx keyInfoWriteCtx - xmlSecTransformCtx transformCtx - # xmlSecTransformUriType enabledReferenceUris - # xmlSecPtrListPtr enabledReferenceTransforms - # xmlSecTransformCtxPreExecuteCallback referencePreExecuteCallback - # xmlSecTransformId defSignMethodId - # xmlSecTransformId defC14NMethodId - # xmlSecTransformId defDigestMethodId - xmlSecKeyPtr signKey - xmlSecTransformOperation operation - # xmlSecBufferPtr result - xmlSecDSigStatus status - xmlSecTransformPtr signMethod - # xmlSecTransformPtr c14nMethod - # xmlSecTransformPtr preSignMemBufMethod - # xmlNode* signValueNode - # xmlChar* id - # xmlSecPtrList signedInfoReferences - # xmlSecPtrList manifestReferences - # void* reserved0 - # void* reserved1 - - ctypedef _xmlSecDSigCtx* xmlSecDSigCtxPtr - - - xmlSecDSigCtxPtr xmlSecDSigCtxCreate(xmlSecKeysMngrPtr) nogil - - int xmlSecDSigCtxSign(xmlSecDSigCtxPtr, xmlNode*) nogil - - int xmlSecDSigCtxProcessSignatureNode(xmlSecDSigCtxPtr, xmlNode*) nogil - - int xmlSecDSigCtxVerify(xmlSecDSigCtxPtr, xmlNode*) nogil - - int xmlSecDSigCtxEnableReferenceTransform( - xmlSecDSigCtxPtr, xmlSecTransformId) nogil - - int xmlSecDSigCtxEnableSignatureTransform( - xmlSecDSigCtxPtr, xmlSecTransformId) nogil - - void xmlSecDSigCtxDestroy(xmlSecDSigCtxPtr) nogil - - xmlID* xmlAddID(xmlValidCtxt* ctx, xmlDoc* doc, const_xmlChar* value, xmlAttr* attr) - - xmlSecTransformPtr xmlSecTransformCtxCreateAndAppend(xmlSecTransformCtxPtr, xmlSecTransformId) nogil - - int xmlSecTransformSetKey(xmlSecTransformPtr, xmlSecKeyPtr) nogil - - int xmlSecTransformSetKeyReq(xmlSecTransformPtr, xmlSecKeyReqPtr) nogil - - int xmlSecTransformVerify(xmlSecTransformPtr, const_xmlSecByte*, xmlSecSize, xmlSecTransformCtxPtr) nogil - - int xmlSecTransformCtxBinaryExecute(xmlSecTransformCtxPtr, const_xmlSecByte*, xmlSecSize) nogil diff --git a/src/xmlsec/ds.pyx b/src/xmlsec/ds.pyx deleted file mode 100644 index 22ceb330..00000000 --- a/src/xmlsec/ds.pyx +++ /dev/null @@ -1,198 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from lxml.includes.tree cimport xmlHasProp, xmlHasNsProp, xmlAttr -from lxml.includes.etreepublic cimport import_lxml__etree -import_lxml__etree() - -from lxml.includes.etreepublic cimport _Element - -from .ds cimport * -from .constants cimport _Transform, xmlSecTransformUsageSignatureMethod -from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ - xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy -from .utils cimport _b -from .error import * - - -__all__ = [ - 'SignatureContext' -] - - -cdef class SignatureContext(object): - """Digital signature context. - """ - - cdef xmlSecDSigCtxPtr _handle - - def __cinit__(self, _KeysManager manager=None): - cdef xmlSecKeysMngrPtr _manager = manager._handle if manager is not None else NULL - cdef xmlSecDSigCtxPtr handle - handle = xmlSecDSigCtxCreate(_manager) - if handle == NULL: - raise InternalError('Failed to create the digital signature context.', -1) - - # Store the constructed context handle. - self._handle = handle - - def __dealloc__(self): - if self._handle != NULL: - xmlSecDSigCtxDestroy(self._handle) - - property key: - def __set__(self, _Key key): - if self._handle.signKey != NULL: - xmlSecKeyDestroy(self._handle.signKey) - - self._handle.signKey = xmlSecKeyDuplicate(key._handle) - if self._handle.signKey == NULL: - raise InternalError("failed to duplicate key", -1) - - def __get__(self): - cdef _Key instance = _Key.__new__(_Key) - instance._owner = False - instance._handle = self._handle.signKey - return instance - - def register_id(self, _Element node not None, id_attr="ID", id_ns=None): - cdef xmlAttr* attr - - if id_ns: - attr = xmlHasNsProp(node._c_node, _b(id_attr), _b(id_ns)) - attrname = '{%s}%s' % (id_ns, id_attr) - else: - attr = xmlHasProp(node._c_node, _b(id_attr)) - attrname = id_attr - value = node.attrib.get(attrname) - - xmlAddID(NULL, node._doc._c_doc, _b(value), attr) - - def sign(self, _Element node not None): - """Sign according to the signature template. - """ - - cdef int rv - - rv = xmlSecDSigCtxSign(self._handle, node._c_node) - if rv != 0: - raise Error('sign failed with return value', rv) - - def verify(self, _Element node not None): - """Verify according to the signature template. - """ - - cdef int rv - - rv = xmlSecDSigCtxVerify(self._handle, node._c_node) - if rv != 0: - raise Error('verify failed with return value', rv) - - if self._handle.status != xmlSecDSigStatusSucceeded: - raise VerificationError('Signature verification failed', self._handle.status) - - def sign_binary(self, bytes data not None, _Transform algorithm not None): - """sign binary data *data* with *algorithm* and return the signature. - You must already have set the context's `signKey` (its value must - be compatible with *algorithm* and signature creation). - """ - - cdef xmlSecDSigCtxPtr context = self._handle - context.operation = xmlSecTransformOperationSign - self._binary(context, data, algorithm) - if context.transformCtx.status != xmlSecTransformStatusFinished: - raise Error("signing failed with transform status", context.transformCtx.status) - res = context.transformCtx.result - return (res.data)[:res.size] - - def verify_binary(self, bytes data not None, _Transform algorithm not None, bytes signature not None): - """Verify *signature* for *data* with *algorithm*. - You must already have set the context's `signKey` (its value must - be compatible with *algorithm* and signature verification). - """ - - cdef int rv - cdef xmlSecDSigCtxPtr context = self._handle - context.operation = xmlSecTransformOperationVerify - self._binary(context, data, algorithm) - rv = xmlSecTransformVerify(context.signMethod, - signature, - len(signature), - &context.transformCtx) - if rv != 0: - raise Error("Verification failed with return value", rv) - - if context.signMethod.status != xmlSecTransformStatusOk: - raise VerificationError("Signature verification failed", context.signMethod.status) - - cdef _binary(self, xmlSecDSigCtxPtr context, bytes data, _Transform algorithm): - """common helper used for `sign_binary` and `verify_binary`.""" - - cdef int rv - cdef const_xmlSecByte* c_data = data - cdef xmlSecSize c_size = len(data) - - if not (algorithm.target.usage & xmlSecTransformUsageSignatureMethod): - raise Error("improper signature algorithm") - - if context.signMethod != NULL: - raise Error("Signature context already used; it is designed for one use only") - - context.signMethod = xmlSecTransformCtxCreateAndAppend(&(context.transformCtx), algorithm.target) - - if context.signMethod == NULL: - raise Error("Could not create signature transform") - - context.signMethod.operation = context.operation - if context.signKey == NULL: - raise Error("signKey not yet set") - - xmlSecTransformSetKeyReq(context.signMethod, &(context.keyInfoReadCtx.keyReq)) - - rv = xmlSecKeyMatch(context.signKey, NULL, &(context.keyInfoReadCtx.keyReq)) - if rv != 1: - raise Error("inappropriate key type") - - rv = xmlSecTransformSetKey(context.signMethod, context.signKey) - if rv != 0: - raise Error("`xmlSecTransfromSetKey` failed", rv) - - context.transformCtx.result = NULL - context.transformCtx.status = xmlSecTransformStatusNone - - rv = xmlSecTransformCtxBinaryExecute(&(context.transformCtx), c_data, c_size) - - if rv != 0: - raise Error("transformation failed error value", rv) - - if context.transformCtx.status != xmlSecTransformStatusFinished: - raise Error("transformation failed with status", context.transformCtx.status) - - def enable_reference_transform(self, _Transform transform): - """enable use of *t* as reference transform. - Note: by default, all transforms are enabled. The first call of - `enableReferenceTransform` will switch to explicitely enabled transforms. - """ - - rv = xmlSecDSigCtxEnableReferenceTransform(self._handle, transform.target) - if rv < 0: - raise Error("enableReferenceTransform failed", rv) - - def enable_signature_transform(self, _Transform transform): - """enable use of *t* as signature transform. - Note: by default, all transforms are enabled. The first call of - `enableSignatureTransform` will switch to explicitely enabled transforms. - """ - - rv = xmlSecDSigCtxEnableSignatureTransform(self._handle, transform.target) - if rv < 0: - raise Error("enableSignatureTransform failed", rv) - - def set_enabled_key_data(self, keydata_list): - cdef _KeyData keydata - cdef xmlSecPtrListPtr enabled_list = &(self._handle.keyInfoReadCtx.enabledKeyData) - xmlSecPtrListEmpty(enabled_list) - for keydata in keydata_list: - rv = xmlSecPtrListAdd(enabled_list, keydata.target) - if rv < 0: - raise Error("setEnabledKeyData failed") diff --git a/src/xmlsec/enc.pxd b/src/xmlsec/enc.pxd deleted file mode 100644 index 7c23fee3..00000000 --- a/src/xmlsec/enc.pxd +++ /dev/null @@ -1,57 +0,0 @@ -from lxml.includes.tree cimport xmlChar, const_xmlChar, xmlNode -from .key cimport xmlSecKeyPtr, xmlSecKeyReqPtr, xmlSecKeysMngrPtr -from .ds cimport const_xmlSecByte, xmlSecBufferPtr - - -cdef extern from "xmlsec.h": # xmlsec/keys.h - - cdef enum: XMLSEC_ENC_RETURN_REPLACED_NODE - - cdef struct _xmlSecEncCtx: - # void * userData - unsigned int flags - # unsigned int flags2 - # xmlEncCtxMode mode - # xmlSecKeyInfoCtx keyInfoReadCtx - # xmlSecKeyInfoCtx keyInfoWriteCtx - # xmlSecTransformCtx transformCtx - # xmlSecTransformId defEncMethodId - xmlSecKeyPtr encKey - # xmlSecTransformOperation operation - xmlSecBufferPtr result - # int resultBase64Encoded - bint resultReplaced - # xmlSecTransformPtr encMethod - # xmlChar* id - # xmlChar* type - # xmlChar* mimeType - # xmlChar* encoding - # xmlChar* recipient - # xmlChar* carriedKeyName - # xmlNode* encDataNode - # xmlNode* encMethodNode - # xmlNode* keyInfoNode - # xmlNode* cipherValueNode - xmlNode* replacedNodeList - # void* reserved1 - - ctypedef _xmlSecEncCtx* xmlSecEncCtxPtr - - xmlSecEncCtxPtr xmlSecEncCtxCreate(xmlSecKeysMngrPtr) nogil - int xmlSecEncCtxInitialize(xmlSecEncCtxPtr encCtx, xmlSecKeysMngrPtr keysMngr) nogil - - void xmlSecEncCtxFinalize(xmlSecEncCtxPtr) nogil - void xmlSecEncCtxDestroy(xmlSecEncCtxPtr) nogil - - int xmlSecEncCtxBinaryEncrypt( - xmlSecEncCtxPtr, xmlNode*, const_xmlSecByte*, size_t) nogil - - int xmlSecEncCtxXmlEncrypt(xmlSecEncCtxPtr, xmlNode*, xmlNode*) nogil - - int xmlSecEncCtxUriEncrypt(xmlSecEncCtxPtr, xmlNode*, const_xmlChar*) nogil - - int xmlSecEncCtxDecrypt(xmlSecEncCtxPtr, xmlNode*) nogil - - void xmlSecErrorsSetCallback(void *callback) nogil - - int xmlSecKeyMatch(xmlSecKeyPtr, const_xmlChar*, xmlSecKeyReqPtr) diff --git a/src/xmlsec/enc.pyx b/src/xmlsec/enc.pyx deleted file mode 100644 index 2ddbe319..00000000 --- a/src/xmlsec/enc.pyx +++ /dev/null @@ -1,230 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from lxml.includes.etreepublic cimport import_lxml__etree -import_lxml__etree() - -from lxml.includes.etreepublic cimport _Document, _Element, elementFactory -from lxml.includes.tree cimport xmlDocCopyNode, xmlFreeNode, xmlDoc, xmlDocGetRootElement - -from .enc cimport * -from .key cimport Key as _Key, KeysManager as _KeysManager, _KeyData, \ - xmlSecKeyDuplicate, xmlSecKeyMatch, xmlSecKeyDestroy -from .utils cimport _b - -from .constants import EncryptionType -from .error import * -from copy import copy - -__all__ = [ - 'EncryptionContext' -] - - -# we let `lxml` get rid of the subtree by wrapping *c_node* into a -# proxy and then releasing it again. -# Note: if referenced by `lxml`, nodes inside the subtree may lack -# necessary namespace daclarations. Hopefully, I can -# convince the `lxml` maintainers to provide a really safe -# `lxml_safe_unlink` function - -cdef inline int _lxml_safe_dealloc(_Document doc, xmlNode* c_node) except -1: - elementFactory(doc, c_node) - return 0 - - - -cdef class EncryptionContext: - """Encryption context.""" - - cdef xmlSecEncCtxPtr _handle - - def __cinit__(self, _KeysManager manager=None): - cdef xmlSecKeysMngrPtr _manager = manager._handle if manager is not None else NULL - cdef xmlSecEncCtxPtr handle = xmlSecEncCtxCreate(_manager) - if handle == NULL: - raise InternalError("failed to create encryption context") - - self._handle = handle - - def __dealloc__(self): - if self._handle != NULL: - xmlSecEncCtxDestroy(self._handle) - - property key: - def __set__(self, _Key key): - if self._handle.encKey != NULL: - xmlSecKeyDestroy(self._handle.encKey) - - self._handle.encKey = xmlSecKeyDuplicate(key._handle) - if self._handle.encKey == NULL: - raise InternalError("failed to duplicate key", -1) - - def __get__(self): - cdef _Key instance = _Key.__new__(_Key) - instance._owner = False - instance._handle = self._handle.encKey - return instance - - def encrypt_binary(self, _Element template not None, data): - """encrypt binary *data* according to `EncryptedData` template *template* - and return the resulting `EncryptedData` subtree. - Note: *template* is modified in place. - """ - cdef int rv - - # Data to bytes - cdef const_xmlSecByte* c_data = data - cdef size_t c_size = len(data) - - with nogil: - rv = xmlSecEncCtxBinaryEncrypt(self._handle, template._c_node, c_data, c_size) - if rv < 0: - raise Error("failed to encrypt binary", rv) - return template - - def encrypt_xml(self, _Element template not None, _Element node not None): - """encrpyt *node* using *template* and return the resulting `EncryptedData` element. - The `Type` attribute of *template* decides whether *node* itself is - encrypted (`http://www.w3.org/2001/04/xmlenc#Element`) - or its content (`http://www.w3.org/2001/04/xmlenc#Content`). - It must have one of these two - values (or an exception is raised). - The operation modifies the tree containing *node* in a way that - `lxml` references to or into this tree may see a surprising state. You - should no longer rely on them. Especially, you should use - `getroottree()` on the result to obtain the encrypted result tree. - """ - - cdef int rv - cdef xmlNode *n - cdef xmlNode *nn - cdef xmlSecEncCtxPtr context = self._handle - cdef xmlNode *c_node = template._c_node - - et = template.get("Type") - if et not in (EncryptionType.ELEMENT, EncryptionType.CONTENT): - raise Error("unsupported `Type` for `encryptXML` (must be `%s` or `%s`)" % (EncryptionType.ELEMENT, EncryptionType.CONTENT), et) - - # `xmlSecEncCtxEncrypt` expects *template* to belong to the document of *node* - # if this is not the case, we copy the `libxml2` subtree there. - - if template._doc._c_doc != node._doc._c_doc: - with nogil: - c_node = xmlDocCopyNode(c_node, node._doc._c_doc, 1) # recursive - if c_node == NULL: - raise MemoryError("could not copy template tree") - - # `xmlSecEncCtxXmlEncrypt` will replace the subtree rooted - # at `node._c_node` or its children by an extended subtree - # rooted at "c_node". - # We set `XMLSEC_ENC_RETURN_REPLACED_NODE` to prevent deallocation - # of the replaced node. This is important as `node` is still - # referencing it - - context.flags = XMLSEC_ENC_RETURN_REPLACED_NODE - - with nogil: - rv = xmlSecEncCtxXmlEncrypt(context, c_node, node._c_node) - - # release the replaced nodes in a way safe for `lxml` - - n = context.replacedNodeList - - while n != NULL: - nn = n.next - _lxml_safe_dealloc(node._doc, n) - n = nn - - context.replacedNodeList = NULL - if rv < 0: - if c_node._private == NULL: - # template tree was copied; free it again. - # Note: if the problem happened late (e.g. a `MemoryError`) - # `c_node' might already be part of the result tree. - # In this case, memory corruption may result. But, - # we have an inconsistent state anyway and the probability - # should be very low. - - with nogil: - xmlFreeNode(c_node) # free formerly copied template subtree - - raise Error("failed to encrypt xml", rv) - - # `c_node` contains the resulting `EncryptedData` element. - return elementFactory(node._doc, c_node) - - def encrypt_uri(self, _Element template not None, uri not None): - """encrypt binary data obtained from *uri* according to *template*.""" - - cdef int rv - cdef const_xmlChar* c_uri = _b(uri) - - with nogil: - rv = xmlSecEncCtxUriEncrypt(self._handle, template._c_node, c_uri) - - if rv < 0: - raise Error("failed to encrypt uri", rv) - return template - - def decrypt(self, _Element node not None): - """decrypt *node* (an `EncryptedData` element) and return the result. - The decryption may result in binary data or an XML subtree. - In the former case, the binary data is returned. In the latter case, - the input tree is modified and a reference to the decrypted - XML subtree is returned. - If the operation modifies the tree, - `lxml` references to or into this tree may see a surprising state. You - should no longer rely on them. Especially, you should use - `getroottree()` on the result to obtain the decrypted result tree. - """ - - cdef int rv - cdef xmlSecEncCtxPtr context = self._handle - cdef bint decrypt_content - cdef xmlNode *n - cdef xmlNode *nn - cdef xmlNode *c_root - cdef xmlSecBufferPtr result - - decrypt_content = node.get("Type") == EncryptionType.CONTENT - - # must provide sufficient context to find the decrypted node - parent = node.getparent() - - if parent is not None: - enc_index = parent.index(node) - - context.flags = XMLSEC_ENC_RETURN_REPLACED_NODE - - with nogil: - rv = xmlSecEncCtxDecrypt(context, node._c_node) - - # release the replaced nodes in a way safe for `lxml` - n = context.replacedNodeList - while n != NULL: - nn = n.next - _lxml_safe_dealloc(node._doc, n) - n = nn - - context.replacedNodeList = NULL - - if rv < 0: - raise Error("failed to decrypt", rv) - - if not context.resultReplaced: - # binary result - result = context.result - return (context.result.data)[:result.size] - # XML result - if parent is not None: - if decrypt_content: - return parent - else: - return parent[enc_index] - - # root has been replaced - c_root = xmlDocGetRootElement(node._doc._c_doc) - if c_root == NULL: - raise Error("decryption resulted in a non well formed document") - return elementFactory(node._doc, c_root) diff --git a/src/xmlsec/error.py b/src/xmlsec/error.py deleted file mode 100644 index 675d5173..00000000 --- a/src/xmlsec/error.py +++ /dev/null @@ -1,15 +0,0 @@ -# -*- coding: utf-8 -*- - -__all__ = ["Error", "VerificationError", "InternalError"] - - -class Error(Exception): - pass - - -class InternalError(Error): - pass - - -class VerificationError(Error): - pass diff --git a/src/xmlsec/key.pxd b/src/xmlsec/key.pxd deleted file mode 100644 index ac188da4..00000000 --- a/src/xmlsec/key.pxd +++ /dev/null @@ -1,122 +0,0 @@ -from lxml.includes.tree cimport const_xmlChar - - -cdef extern from *: - ctypedef char const_char "const char" - ctypedef unsigned char const_unsigned_char "const unsigned char" - - -cdef extern from "xmlsec.h": # xmlsec/keys.h - - cdef struct _xmlSecKeyDataKlass: - const_xmlChar* name - const_xmlChar* href - - ctypedef _xmlSecKeyDataKlass *xmlSecKeyDataId - - xmlSecKeyDataId xmlSecKeyDataNameGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataValueGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataRetrievalMethodGetKlass() nogil - xmlSecKeyDataId xmlSecKeyDataEncryptedKeyGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataAesGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataDesGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataDsaGetKlass() nogil - # xmlSecKeyDataId xmlSecOpenSSLKeyDataEcdsaGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataHmacGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataRsaGetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataX509GetKlass() nogil - xmlSecKeyDataId xmlSecOpenSSLKeyDataRawX509CertGetKlass() nogil - - ctypedef enum xmlSecKeyDataFormat: - xmlSecKeyDataFormatUnknown = 0 - xmlSecKeyDataFormatBinary = 1 - xmlSecKeyDataFormatPem = 2 - xmlSecKeyDataFormatDer = 3 - xmlSecKeyDataFormatPkcs8Pem = 4 - xmlSecKeyDataFormatPkcs8Der = 5 - xmlSecKeyDataFormatPkcs12 = 6 - xmlSecKeyDataFormatCertPem = 7 - xmlSecKeyDataFormatCertDer = 8 - - ctypedef unsigned int xmlSecKeyDataType - - cdef enum: - xmlSecKeyDataTypeUnknown = 0x0000 - xmlSecKeyDataTypeNone = 0x0000 - xmlSecKeyDataTypePublic = 0x0001 - xmlSecKeyDataTypePrivate = 0x0002 - xmlSecKeyDataTypeSymmetric = 0x0004 - xmlSecKeyDataTypeSession = 0x0008 - xmlSecKeyDataTypePermanent = 0x0010 - xmlSecKeyDataTypeTrusted = 0x0100 - xmlSecKeyDataTypeAny = 0xFFFF - - ctypedef void* xmlSecKeyPtr - - cdef struct _xmlSecKeyReq: - pass - - ctypedef _xmlSecKeyReq xmlSecKeyReq - ctypedef xmlSecKeyReq* xmlSecKeyReqPtr - - void xmlSecKeyDestroy(xmlSecKeyPtr) nogil - - xmlSecKeyPtr xmlSecKeyDuplicate(xmlSecKeyPtr) nogil - - xmlSecKeyPtr xmlSecOpenSSLAppKeyLoad( - const_char*, xmlSecKeyDataFormat, const_char*, void*, void *) nogil - - xmlSecKeyPtr xmlSecOpenSSLAppKeyLoadMemory( - const_unsigned_char*, int, xmlSecKeyDataFormat, - const_char*, void*, void*) nogil - - xmlSecKeyPtr xmlSecKeyReadBinaryFile(xmlSecKeyDataId, const_char*) nogil - - # xmlSecKeyPtr xmlSecKeyReadMemory( - # xmlSecKeyDataId, const_unsigned_char*, size_t) nogil - - int xmlSecOpenSSLAppKeyCertLoad( - xmlSecKeyPtr, const_char*, xmlSecKeyDataFormat) nogil - - int xmlSecOpenSSLAppKeyCertLoadMemory( - xmlSecKeyPtr, const_unsigned_char*, int, xmlSecKeyDataFormat) nogil - - xmlSecKeyPtr xmlSecKeyGenerate( - xmlSecKeyDataId, size_t, xmlSecKeyDataType) nogil - - int xmlSecKeySetName(xmlSecKeyPtr, const_xmlChar*) nogil - - const_xmlChar* xmlSecKeyGetName(xmlSecKeyPtr) nogil - - int xmlSecKeyMatch(xmlSecKeyPtr, const_xmlChar *, xmlSecKeyReqPtr) nogil - - ctypedef void *xmlSecKeysMngrPtr - - xmlSecKeysMngrPtr xmlSecKeysMngrCreate() nogil - - void xmlSecKeysMngrDestroy(xmlSecKeysMngrPtr) nogil - - int xmlSecOpenSSLAppDefaultKeysMngrInit(xmlSecKeysMngrPtr) nogil - - int xmlSecOpenSSLKeysMngrInit(xmlSecKeysMngrPtr) nogil - - int xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(xmlSecKeysMngrPtr, xmlSecKeyPtr) nogil - - int xmlSecOpenSSLAppKeysMngrCertLoad( - xmlSecKeysMngrPtr, char * filename, xmlSecKeyDataFormat, xmlSecKeyDataType) nogil - - int xmlSecOpenSSLAppKeysMngrCertLoadMemory( - xmlSecKeysMngrPtr, const_unsigned_char *, size_t, xmlSecKeyDataFormat, xmlSecKeyDataType) nogil - - -cdef class _KeyData(object): - cdef xmlSecKeyDataId target - - -cdef class Key(object): - cdef xmlSecKeyPtr _handle - cdef bint _owner - - -cdef class KeysManager(object): - cdef xmlSecKeysMngrPtr _handle diff --git a/src/xmlsec/key.pyx b/src/xmlsec/key.pyx deleted file mode 100644 index f19c2ae7..00000000 --- a/src/xmlsec/key.pyx +++ /dev/null @@ -1,319 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from .key cimport * -from .utils cimport _b, _u -from .error import * -from copy import copy -from .ssl cimport ERR_clear_error - -__all__ = [ - 'KeyData', - 'KeyDataType', - 'KeyFormat', - 'Key', - 'KeysManager' -] - - -class KeyFormat: - UNKNOWN = xmlSecKeyDataFormatUnknown - BINARY = xmlSecKeyDataFormatBinary - PEM = xmlSecKeyDataFormatPem - DER = xmlSecKeyDataFormatDer - PKCS8_PEM = xmlSecKeyDataFormatPkcs8Pem - PKCS8_DER = xmlSecKeyDataFormatPkcs8Der - PKCS12_PEM = xmlSecKeyDataFormatPkcs12 - CERT_PEM = xmlSecKeyDataFormatCertPem - CERT_DER = xmlSecKeyDataFormatCertDer - - -cdef class _KeyData(object): - property name: - def __get__(self): - return _u(self.id.name) - - property href: - def __get__(self): - return _u(self.id.href) - - -cdef _KeyData _mkkdi(xmlSecKeyDataId target): - cdef _KeyData r = _KeyData.__new__(_KeyData) - r.target = target - return r - - -cdef class KeyData(object): - NAME = _mkkdi(xmlSecKeyDataNameGetKlass()) - VALUE = _mkkdi(xmlSecKeyDataValueGetKlass()) - RETRIEVALMETHOD = _mkkdi(xmlSecKeyDataRetrievalMethodGetKlass()) - ENCRYPTEDKEY = _mkkdi(xmlSecKeyDataEncryptedKeyGetKlass()) - AES = _mkkdi(xmlSecOpenSSLKeyDataAesGetKlass()) - DES = _mkkdi(xmlSecOpenSSLKeyDataDesGetKlass()) - DSA = _mkkdi(xmlSecOpenSSLKeyDataDsaGetKlass()) - # ECDSA = _mkkdi(xmlSecOpenSSLKeyDataEcdsaGetKlass()) - HMAC = _mkkdi(xmlSecOpenSSLKeyDataHmacGetKlass()) - RSA = _mkkdi(xmlSecOpenSSLKeyDataRsaGetKlass()) - X509 = _mkkdi(xmlSecOpenSSLKeyDataX509GetKlass()) - RAWX509CERT = _mkkdi(xmlSecOpenSSLKeyDataRawX509CertGetKlass()) - - -cdef class KeyDataType(object): - UNKNOWN = xmlSecKeyDataTypeUnknown - NONE = xmlSecKeyDataTypeNone - PUBLIC = xmlSecKeyDataTypePublic - PRIVATE = xmlSecKeyDataTypePrivate - SYMMETRIC = xmlSecKeyDataTypeSymmetric - SESSION = xmlSecKeyDataTypeSession - PERMANENT = xmlSecKeyDataTypePermanent - TRUSTED = xmlSecKeyDataTypeTrusted - ANY = xmlSecKeyDataTypeAny - - -cdef class Key(object): - - def __init__(self): - self._handle = NULL - self._owner = True - - def __dealloc__(self): - if self._owner and self._handle != NULL: - xmlSecKeyDestroy(self._handle) - self._handle = NULL - - def __deepcopy__(self): - return self.__copy__() - - def __copy__(self): - cdef Key instance = type(self)() - instance._handle = xmlSecKeyDuplicate(self._handle) - if instance._handle == NULL: - raise InternalError("failed to duplicate key", -1) - - return instance - - @classmethod - def from_memory(cls, data, xmlSecKeyDataFormat format, password=None): - """Load PKI key from memory. - """ - - cdef xmlSecKeyPtr handle - cdef size_t c_size - cdef const_unsigned_char *c_data - cdef const_char* c_password = _b(password) - cdef Key instance - - if hasattr(data, "read"): - data = data.read() - - if isinstance(data, str): - data = data.encode('utf8') - - c_size = len(data) - c_data = data - - with nogil: - handle = xmlSecOpenSSLAppKeyLoadMemory( - c_data, c_size, format, c_password, NULL, NULL) - - if handle == NULL: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError("failed to load key") - - # Construct and return a new instance. - instance = cls() - instance._handle = handle - return instance - - @classmethod - def from_file(cls, filename, xmlSecKeyDataFormat format, password=None): - """Load PKI key from a file. - """ - - cdef xmlSecKeyPtr handle - cdef const_char* c_filename = _b(filename) - cdef const_char* c_password = _b(password) - cdef Key instance - - with nogil: - handle = xmlSecOpenSSLAppKeyLoad( - c_filename, format, c_password, NULL, NULL) - - if handle == NULL: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError("failed to load key from '%s'" % filename) - - # Construct and return a new instance. - instance = cls() - instance._handle = handle - return instance - - @classmethod - def generate(cls, _KeyData data, size_t size, xmlSecKeyDataType type): - """Generate key of kind *data* with *size* and *type*. - """ - - cdef xmlSecKeyPtr handle - cdef xmlSecKeyDataId data_id = data.target - cdef Key instance - - with nogil: - handle = xmlSecKeyGenerate(data_id, size, type) - - if handle == NULL: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError("failed to generate key") - - # Construct and return a new instance. - instance = cls() - instance._handle = handle - return instance - - @classmethod - def from_binary_file(cls, _KeyData data, filename): - """load (symmetric) key from file. - load key of kind *data* from *filename* - """ - cdef xmlSecKeyPtr handle - cdef const_char* c_filename = _b(filename) - cdef xmlSecKeyDataId data_id = data.target - cdef Key instance - - with nogil: - handle = xmlSecKeyReadBinaryFile(data_id, c_filename) - - if handle == NULL: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError("failed to load from '%s'" % filename) - - # Construct and return a new instance. - instance = cls() - instance._handle = handle - return instance - - - def load_cert_from_memory(self, data, xmlSecKeyDataFormat format): - cdef int rv - cdef size_t c_size - cdef const_unsigned_char *c_data - - if isinstance(data, str): - data = data.encode('utf8') - c_size = len(data) - c_data = data - - with nogil: - rv = xmlSecOpenSSLAppKeyCertLoadMemory( - self._handle, c_data, c_size, format) - - if rv != 0: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError('Failed to load the certificate from the I/O stream.') - - def load_cert_from_file(self, filename, xmlSecKeyDataFormat format): - cdef int rv - cdef const_char* c_filename = _b(filename) - cdef Key instance - - with nogil: - rv = xmlSecOpenSSLAppKeyCertLoad(self._handle, c_filename, format) - - if rv != 0: - # Clear the error stack generated from openssl - ERR_clear_error() - - raise ValueError('Failed to load the certificate from the file.') - - property name: - def __get__(self): - if self._handle != NULL: - return _u(xmlSecKeyGetName(self._handle)) - else: - raise ValueError('Not ready.') - - def __set__(self, value): - if self._handle != NULL: - xmlSecKeySetName(self._handle, _b(value)) - else: - raise ValueError('Not ready.') - - -cdef class KeysManager(object): - def __cinit__(self): - cdef int rv - cdef xmlSecKeysMngrPtr handle - - handle = xmlSecKeysMngrCreate() - if handle == NULL: - raise InternalError("failed to create keys manager", -1) - rv = xmlSecOpenSSLAppDefaultKeysMngrInit(handle) - if rv < 0: - xmlSecKeysMngrDestroy(handle) - raise InternalError("failed to init manager", rv) - - self._handle = handle - - def __dealloc__(self): - if self._handle != NULL: - xmlSecKeysMngrDestroy(self._handle) - - def add_key(self, Key key): - """add (a copy of) *key*.""" - - cdef int rv - if key._handle == NULL: - raise ValueError("invalid key") - - cdef xmlSecKeyPtr key_handle = xmlSecKeyDuplicate(key._handle) - if key_handle == NULL: - raise InternalError("failed to copy key", -1) - - rv = xmlSecOpenSSLAppDefaultKeysMngrAdoptKey(self._handle, key_handle) - if rv < 0: - xmlSecKeyDestroy(key_handle) - raise Error("failed to add key", rv) - - def load_cert(self, filename, xmlSecKeyDataFormat format, xmlSecKeyDataType type): - """load certificate from *filename*. - *format* specifies the key data format. - *type* specifies the type and is an or of `KeyDataType*` constants. - """ - cdef int rv - cdef const_char* c_filename = _b(filename) - - with nogil: - rv = xmlSecOpenSSLAppKeysMngrCertLoad(self._handle, c_filename, format, type) - - if rv != 0: - raise Error("failed to load certificate from '%s'" % filename, rv) - - def load_cert_from_memory(self, data, xmlSecKeyDataFormat format, xmlSecKeyDataType type): - """load certificate from *data* (a sequence of bytes). - *format* specifies the key_data_format. - *type* specifies the type and is an or of `KeyDataType*` constants. - """ - cdef int rv - cdef size_t c_size - cdef const_unsigned_char *c_data - - if isinstance(data, str): - data = data.encode('utf8') - c_size = len(data) - c_data = data - - with nogil: - rv = xmlSecOpenSSLAppKeysMngrCertLoadMemory(self._handle, c_data, c_size, format, type) - - if rv != 0: - raise Error("failed to load certificate from memory", rv) diff --git a/src/xmlsec/meta.py b/src/xmlsec/meta.py deleted file mode 100644 index 9ea72b40..00000000 --- a/src/xmlsec/meta.py +++ /dev/null @@ -1,2 +0,0 @@ -version = '0.6.0' -description = 'Python bindings for the XML Security Library.' diff --git a/src/xmlsec/ssl.pxd b/src/xmlsec/ssl.pxd deleted file mode 100644 index 90b2fd09..00000000 --- a/src/xmlsec/ssl.pxd +++ /dev/null @@ -1,4 +0,0 @@ - - -cdef extern from "xmlsec.h": - void ERR_clear_error() nogil diff --git a/src/xmlsec/template.pxd b/src/xmlsec/template.pxd deleted file mode 100644 index 4994e8be..00000000 --- a/src/xmlsec/template.pxd +++ /dev/null @@ -1,51 +0,0 @@ -from lxml.includes.tree cimport const_xmlChar, xmlNode, xmlDoc -from .constants cimport xmlSecTransformId - - -cdef extern from "xmlsec.h": # xmlsec/templates.h - - xmlNode* xmlSecTmplSignatureCreateNsPref( - xmlDoc* document, xmlSecTransformId c14n, xmlSecTransformId sign, - const_xmlChar* id, const_xmlChar* ns) nogil - - xmlNode* xmlSecTmplSignatureAddReference( - xmlNode* node, xmlSecTransformId digest, - const_xmlChar* id, const_xmlChar* uri, const_xmlChar* type) nogil - - xmlNode* xmlSecTmplReferenceAddTransform( - xmlNode* node, xmlSecTransformId transform) nogil - - xmlNode* xmlSecTmplSignatureEnsureKeyInfo( - xmlNode* node, const_xmlChar* id) nogil - - xmlNode* xmlSecTmplKeyInfoAddKeyName(xmlNode* node, const_xmlChar* name) nogil - - xmlNode* xmlSecTmplKeyInfoAddKeyValue(xmlNode* node) nogil - - xmlNode* xmlSecTmplKeyInfoAddX509Data(xmlNode* node) nogil - - xmlNode* xmlSecTmplX509DataAddIssuerSerial(xmlNode* node) nogil - - xmlNode* xmlSecTmplX509IssuerSerialAddIssuerName(xmlNode* node, const_xmlChar* name) nogil - - xmlNode* xmlSecTmplX509IssuerSerialAddSerialNumber(xmlNode* node, const_xmlChar* serial) nogil - - xmlNode* xmlSecTmplX509DataAddSubjectName(xmlNode* node) nogil - - xmlNode* xmlSecTmplX509DataAddSKI(xmlNode* node) nogil - - xmlNode* xmlSecTmplX509DataAddCertificate(xmlNode* node) nogil - - xmlNode* xmlSecTmplX509DataAddCRL(xmlNode* node) nogil - - xmlNode* xmlSecTmplKeyInfoAddEncryptedKey( - xmlNode* keyInfoNode, xmlSecTransformId encMethodId, - const_xmlChar *id, const_xmlChar *type, const_xmlChar *recipient) nogil - - xmlNode* xmlSecTmplEncDataCreate( - xmlDoc* doc, xmlSecTransformId encMethodId, const_xmlChar *id, - const_xmlChar *type, const_xmlChar *mimeType, const_xmlChar *encoding) nogil - - xmlNode* xmlSecTmplEncDataEnsureKeyInfo(xmlNode* encNode, const_xmlChar *id) nogil - - xmlNode* xmlSecTmplEncDataEnsureCipherValue(xmlNode* encNode) nogil diff --git a/src/xmlsec/template.pyx b/src/xmlsec/template.pyx deleted file mode 100644 index d63bf2dd..00000000 --- a/src/xmlsec/template.pyx +++ /dev/null @@ -1,217 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from lxml.includes.etreepublic cimport import_lxml__etree -import_lxml__etree() - -from .template cimport * -from lxml.includes.etreepublic cimport _Element, elementFactory -from lxml.includes.tree cimport xmlStrdup -from .constants cimport _Transform -from .utils cimport _b - - -def create(_Element node not None, - _Transform c14n_method not None, - _Transform sign_method not None, - name=None, - ns=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_name = _b(name) - cdef const_xmlChar* c_ns = _b(ns) - - c_node = xmlSecTmplSignatureCreateNsPref( - node._doc._c_doc, c14n_method.target, sign_method.target, c_name, c_ns) - - return elementFactory(node._doc, c_node) - - -def add_reference(_Element node not None, - _Transform digest_method not None, - id=None, uri=None, type=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_id = _b(id) - cdef const_xmlChar* c_uri = _b(uri) - cdef const_xmlChar* c_type = _b(type) - - c_node = xmlSecTmplSignatureAddReference( - node._c_node, digest_method.target, c_id, c_uri, c_type) - - return elementFactory(node._doc, c_node) - - -def add_transform(_Element node not None, _Transform transform not None): - cdef xmlNode* c_node - - c_node = xmlSecTmplReferenceAddTransform( - node._c_node, transform.target) - - return elementFactory(node._doc, c_node) - - -def ensure_key_info(_Element node not None, id=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_id = _b(id) - - c_node = xmlSecTmplSignatureEnsureKeyInfo(node._c_node, c_id) - - return elementFactory(node._doc, c_node) - - -def add_key_name(_Element node not None, name=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_name = _b(name) - - c_node = xmlSecTmplKeyInfoAddKeyName(node._c_node, c_name) - - return elementFactory(node._doc, c_node) - - -def add_key_value(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplKeyInfoAddKeyValue(node._c_node) - - return elementFactory(node._doc, c_node) - - -def add_x509_data(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplKeyInfoAddX509Data(node._c_node) - - return elementFactory(node._doc, c_node) - - -def x509_data_add_issuer_serial(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplX509DataAddIssuerSerial(node._c_node) - - return elementFactory(node._doc, c_node) - - -def x509_issuer_serial_add_issuer_name(_Element node not None, name=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_name = _b(name) - - c_node = xmlSecTmplX509IssuerSerialAddIssuerName(node._c_node, c_name) - - return elementFactory(node._doc, c_node) - - -def x509_issuer_serial_add_serial_number(_Element node not None, serial=None): - - cdef xmlNode* c_node - cdef const_xmlChar* c_serial = _b(serial) - - c_node = xmlSecTmplX509IssuerSerialAddSerialNumber(node._c_node, c_serial) - - return elementFactory(node._doc, c_node) - - -def x509_data_add_subject_name(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplX509DataAddSubjectName(node._c_node) - - return elementFactory(node._doc, c_node) - - -def x509_data_add_ski(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplX509DataAddSKI(node._c_node) - - return elementFactory(node._doc, c_node) - - -def x509_data_add_certificate(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplX509DataAddCertificate(node._c_node) - - return elementFactory(node._doc, c_node) - - -def x509_data_add_crl(_Element node not None): - - cdef xmlNode* c_node - - c_node = xmlSecTmplX509DataAddCRL(node._c_node) - - return elementFactory(node._doc, c_node) - - -def add_encrypted_key(_Element node not None, - _Transform method not None, - id=None, - type=None, - recipient=None): - """Adds node with given attributes to the node keyInfoNode. - """ - - cdef xmlNode* c_node - cdef const_xmlChar* c_id = _b(id) - cdef const_xmlChar* c_type = _b(type) - cdef const_xmlChar* c_recipient = _b(recipient) - - c_node = xmlSecTmplKeyInfoAddEncryptedKey(node._c_node, method.target, c_id, c_type, c_recipient) - return elementFactory(node._doc, c_node) - - -def encrypted_data_create(_Element node not None, - _Transform method not None, - id=None, - type=None, - mime_type=None, - encoding=None, - ns=None): - """ - Creates new <{ns}:EncryptedData /> node for encryption template. - """ - cdef xmlNode* c_node - cdef const_xmlChar* c_id = _b(id) - cdef const_xmlChar* c_type = _b(type) - cdef const_xmlChar* c_mtype = _b(mime_type) - cdef const_xmlChar* c_encoding = _b(encoding) - - c_node = xmlSecTmplEncDataCreate( - node._doc._c_doc, method.target, c_id, c_type, c_mtype, c_encoding) - - if ns is not None: - c_node.ns.prefix = xmlStrdup(_b(ns)) - return elementFactory(node._doc, c_node) - - -def encrypted_data_ensure_key_info(_Element node not None, id=None, ns=None): - """ - Adds <{ns}:KeyInfo/> to the node encNode. - """ - - cdef xmlNode* c_node - cdef const_xmlChar* c_id = _b(id) - - c_node = xmlSecTmplEncDataEnsureKeyInfo(node._c_node, c_id) - if ns is not None: - c_node.ns.prefix = xmlStrdup(_b(ns)) - - return elementFactory(node._doc, c_node) - - -def encrypted_data_ensure_cipher_value(_Element node not None): - cdef xmlNode* c_node - c_node = xmlSecTmplEncDataEnsureCipherValue(node._c_node) - - return elementFactory(node._doc, c_node) diff --git a/src/xmlsec/tree.pxd b/src/xmlsec/tree.pxd deleted file mode 100644 index 1865fbe7..00000000 --- a/src/xmlsec/tree.pxd +++ /dev/null @@ -1,68 +0,0 @@ -from lxml.includes.tree cimport const_xmlChar, xmlNode, xmlDoc - - -cdef extern from "xmlsec.h": # xmlsec/xmltree.h - - # const_xmlChar* xmlSecGetNodeNsHref(xmlNode* node) - - # bint xmlSecCheckNodeName( - # xmlNode* node, const_xmlChar* name, const_xmlChar* ns) - - # xmlNode* xmlSecGetNextElementNode(xmlNode* node) - - xmlNode* xmlSecFindChild( - xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) nogil - - xmlNode* xmlSecFindParent( - xmlNode* node, const_xmlChar* name, const_xmlChar* ns) nogil - - xmlNode* xmlSecFindNode( - xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) nogil - - # xmlNode* xmlSecAddChild( - # xmlNode* parent, const_xmlChar* name, const_xmlChar* ns) - - # xmlNode* xmlSecAddChildNode(xmlNode* parent, xmlNode* child) - - # xmlNode* xmlSecAddNextSibling( - # xmlNode* node, const_xmlChar* name, const_xmlChar* ns) - - # xmlNode* xmlSecAddPrevSibling( - # xmlNode* node, const_xmlChar* name, const_xmlChar* ns) - - # int xmlSecReplaceNode(xmlNode* node, xmlNode* new_node) - - # int xmlSecReplaceNodeAndReturn( - # xmlNode* node, xmlNode* new_node, xmlNode** replaced) - - # int xmlSecReplaceContent(xmlNode* node, xmlNode* new_node) - - # int xmlSecReplaceContentAndReturn( - # xmlNode* node, xmlNode* new_node, xmlNode** replaced) - - # int xmlSecReplaceNodeBuffer( - # xmlNode* node, const_xmlSecByte* buffer, xmlSecSize size) - - # int xmlSecReplaceNodeBufferAndReturn( - # xmlNode* node, const_xmlSecByte* buffer, xmlSecSize size, - # xmlNode** replaced) - - # int xmlSecNodeEncodeAndSetContent(xmlNode* node, const_xmlChar* buffer) - - int xmlSecAddIDs(xmlDoc* document, xmlNode* node, const_xmlChar** ids) nogil - - # int xmlSecGenerateAndAddID( - # xmlNode* node, const_xmlChar* name, const_xmlChar* prefix) - - # xmlChar* xmlSecGenerateID(const_xmlChar* prefix, xmlSecSize length) - - # xmlDoc* xmlSecCreateTree(const_xmlChar* name, const_xmlChar* ns) - - # bint xmlSecIsEmptyNode(xmlNode* node) - - # bint xmlSecIsEmptyString(const_xmlChar* text) - - # xmlChar* xmlSecGetQName( - # xmlNode* node, const_xmlChar* href, const_xmlChar* local) - - # int xmlSecPrintXmlString(FILE*, const_xmlChar* text) diff --git a/src/xmlsec/tree.pyx b/src/xmlsec/tree.pyx deleted file mode 100644 index 42c47461..00000000 --- a/src/xmlsec/tree.pyx +++ /dev/null @@ -1,84 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from libc cimport stdlib -from lxml.includes.etreepublic cimport import_lxml__etree -import_lxml__etree() - -from lxml.includes.etreepublic cimport _ElementTree, _Element, elementFactory -from .tree cimport * -from .utils cimport _b -from .constants import Namespace - - -__all__ = [ - 'find_child', - 'find_parent', - 'find_node', - 'add_ids' -] - - -def find_child(_Element parent not None, - name not None, - namespace=Namespace.DS): - """ - Searches a direct child of the parent node having given name and - namespace href. - """ - cdef xmlNode* c_node - c_node = xmlSecFindChild(parent._c_node, _b(name), _b(namespace)) - return elementFactory(parent._doc, c_node) if c_node else None - - -def find_parent(_Element node not None, - name not None, - namespace=Namespace.DS): - """ - Searches the ancestors axis of the node for a node having given name - and namespace href. - """ - cdef xmlNode* c_node - c_node = xmlSecFindParent(node._c_node, _b(name), _b(namespace)) - return elementFactory(node._doc, c_node) if c_node else None - - -def find_node(_Element parent not None, - name not None, - namespace=Namespace.DS): - """ - Searches all children of the parent node having given name and - namespace href. - """ - cdef xmlNode* c_node - c_node = xmlSecFindNode(parent._c_node, _b(name), _b(namespace)) - return elementFactory(parent._doc, c_node) if c_node else None - - - -def add_ids(_Element node, ids): - """register *ids* as ids used below *node*. - *ids* is a sequence of attribute names used as XML ids in the subtree - rooted at *node*. - A call to `addIds` may be necessary to make known which attributes - contain XML ids. This is the case, if a transform references - an id via `XPointer` or a self document uri and the id - inkey_data_formation is not available by other means (e.g. an associated - DTD or XML schema). - """ - - cdef const_xmlChar **lst - cdef int i, n - - n = len(ids) - lst = stdlib.malloc(sizeof(const_xmlChar*) * (n + 1)) - if lst == NULL: - raise MemoryError - try: - for i in range(n): - lst[i] = _b(ids[i]) - lst[n] = NULL - with nogil: - xmlSecAddIDs(node._doc._c_doc, node._c_node, lst) - finally: - stdlib.free(lst) diff --git a/src/xmlsec/utils.pxd b/src/xmlsec/utils.pxd deleted file mode 100644 index 86e828df..00000000 --- a/src/xmlsec/utils.pxd +++ /dev/null @@ -1,33 +0,0 @@ -from lxml.includes.tree cimport const_xmlChar - - -cdef inline const_xmlChar* _b(text): - if text is None: - return NULL - - if isinstance(text, str): - text = text.encode('utf8') - return text - - return text - - -cdef inline _u(const_xmlChar* text): - return text.decode('utf8') if text != NULL else None - - -cdef extern from "xmlsec.h": # xmlsec/xmlsec.h - int xmlSecInit() nogil - int xmlSecShutdown() nogil - - -cdef extern from "xmlsec.h": # xmlsec/errors.h - int xmlSecErrorsDefaultCallbackEnableOutput(int) nogil - - -cdef extern from "xmlsec.h": # xmlsec/openssl/app.h - int xmlSecOpenSSLInit() nogil - int xmlSecOpenSSLShutdown() nogil - - int xmlSecOpenSSLAppInit(char* name) nogil - int xmlSecOpenSSLAppShutdown() nogil diff --git a/src/xmlsec/utils.pyx b/src/xmlsec/utils.pyx deleted file mode 100644 index 94e7fd26..00000000 --- a/src/xmlsec/utils.pyx +++ /dev/null @@ -1,53 +0,0 @@ -# -*- coding: utf-8 -*- -from __future__ import absolute_import, unicode_literals, division - -from .utils cimport * - -__all__ = [ - 'init', - 'shutdown', - 'enable_debug_trace' -] - - -def init(): - """Initialize the library for general operation. - - This is called upon library import and does not need to be called - again (unless @ref _shutdown is called explicitly). - """ - if xmlSecInit() < 0: - return False - - if xmlSecOpenSSLAppInit(NULL) < 0: - xmlSecShutdown() - return False - - if xmlSecOpenSSLInit() < 0: - xmlSecOpenSSLAppShutdown() - xmlSecShutdown() - return False - - return True - - -def shutdown(): - """Shutdown the library and cleanup any leftover resources. - - This is called automatically upon interpreter termination and - should not need to be called explicitly. - """ - if xmlSecOpenSSLShutdown() < 0: - return False - - if xmlSecOpenSSLAppShutdown() < 0: - return False - - if xmlSecShutdown() < 0: - return False - - return True - - -def enable_debug_trace(flag): - xmlSecErrorsDefaultCallbackEnableOutput(1 if flag else 0) diff --git a/tests/examples/test_decrypt.py b/tests/examples/test_decrypt.py index f17f00f2..b06771b6 100644 --- a/tests/examples/test_decrypt.py +++ b/tests/examples/test_decrypt.py @@ -37,7 +37,7 @@ def test_decrypt2(): enc_ctx = xmlsec.EncryptionContext(manager) root = parse_xml("enc2-res.xml") - enc_data = xmlsec.tree.find_child(root, xmlsec.constants.Node.ENCRYPTED_DATA, xmlsec.Namespace.ENC) + enc_data = xmlsec.tree.find_child(root, xmlsec.Node.ENCRYPTED_DATA, xmlsec.Namespace.ENC) assert enc_data is not None decrypted = enc_ctx.decrypt(enc_data) assert decrypted.text == "\ntest\n" diff --git a/tests/examples/test_verify.py b/tests/examples/test_verify.py index 4e2381bb..7d8c2054 100644 --- a/tests/examples/test_verify.py +++ b/tests/examples/test_verify.py @@ -57,3 +57,26 @@ def test_validate_binary_sign(): data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" ctx.verify_binary(data, xmlsec.Transform.RSA_SHA1, sign) + + +def test_validate_binary_sign_fail(): + ctx = xmlsec.SignatureContext() + filename = path.join(BASE_DIR, 'rsakey.pem') + key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) + assert key is not None + + key.name = path.basename(filename) + + # Set the key on the context. + ctx.key = key + + assert ctx.key is not None + assert ctx.key.name == path.basename(filename) + + data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' + sign = b"invalid" + try: + ctx.verify_binary(data, xmlsec.Transform.RSA_SHA1, sign) + assert False + except xmlsec.Error: + pass From 2dda5080d297f7065e9e4f27346e8aea1b368b4d Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Mon, 30 Jan 2017 12:11:35 +0300 Subject: [PATCH 032/378] Added note about installation requirements --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 17d66502..24b177d6 100644 --- a/README.md +++ b/README.md @@ -8,6 +8,10 @@ Check the [examples](https://github.com/mehcode/python-xmlsec/tree/master/tests/examples) to see various examples of signing and verifying using the library. +## Requirements +- libxml2 >= 2.9.1 +- libxmlsec1 >= 1.2.14 + ## Install ### Pre-Install @@ -18,6 +22,15 @@ Check the [examples](https://github.com/mehcode/python-xmlsec/tree/master/tests/ apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-opensssl ``` +Note: There is no required version of libxml2 for ubuntu precise, +so need to dowload and install it manually. +```sh +wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz +tar -xvf libxml2-2.9.1.tar.gz +cd libxml2-2.9.1 +./configure && make && make install +``` + #### Linux (CentOS) ```sh From ee6f18415b3cc50e17b1c7331b44cc0bccc3e1d0 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 14 Feb 2017 23:14:03 +0300 Subject: [PATCH 033/378] Fixed installation via pip #39 --- setup.py | 59 +++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index 2837cbae..fb29aa56 100644 --- a/setup.py +++ b/setup.py @@ -2,15 +2,13 @@ import glob import os -import pkgconfig from setuptools import setup from setuptools import Extension -import sys +from setuptools.command import build_ext -import lxml __name__ = "xmlsec" -__version__ = "1.0.1" +__version__ = "1.0.2" __description__ = "Python bindings for the XML Security Library" @@ -29,33 +27,55 @@ def is_debug(): cflags.extend(["-Os"]) -config = pkgconfig.parse("xmlsec1") +def add_to_list(target, up): + if up is None: + return target + value = set(target) + value.update(up) + target[:] = list(value) -def add_to_config(key, args): - value = list(config.get(key, [])) - value.extend(args) - config[key] = value +def find_sources(path): + return glob.glob(os.path.join(path, "*.c")) -add_to_config('define_macros', macroses) -add_to_config('include_dirs', lxml.get_include()) -print(config, file=sys.stderr) +def parse_requirements(filename, __cache={}): + try: + return __cache[filename] + except KeyError: + with open(filename) as stream: + result = __cache[filename] = [x for x in (y.strip() for y in stream) if x and not x.startswith('#')] + return result -def find_sources(path): - return glob.glob(os.path.join(path, "*.c")) +class BuildExt(build_ext.build_ext): + def run(self): + self.patch_xmlsec() + build_ext.build_ext.run(self) + + def patch_xmlsec(self): + # at this moment all setup_requires are installed and we can safety import them + pkgconfig = __import__("pkgconfig") + lxml = __import__("lxml") + + ext = self.ext_map[__name__] + config = pkgconfig.parse("xmlsec1") + # added build flags from pkg-config + for item in ('define_macros', 'libraries', 'library_dirs', 'include_dirs'): + add_to_list(getattr(ext, item), config.get(item)) + + add_to_list(ext.include_dirs, lxml.get_include()) _xmlsec = Extension( __name__, sources=find_sources("./src"), extra_compile_args=cflags, - libraries=list(config.get('libraries', [])), - library_dirs=list(config.get('library_dirs', [])), - include_dirs=list(config.get('include_dirs', [])), - define_macros=config['define_macros'] + libraries=[], + library_dirs=[], + include_dirs=[], + define_macros=macroses ) setup( @@ -63,6 +83,9 @@ def find_sources(path): version=__version__, description=__description__, ext_modules=[_xmlsec], + cmdclass={'build_ext': BuildExt}, + setup_requires=parse_requirements('requirements.txt'), + install_requires=parse_requirements('requirements.txt'), author="Ryan Leckey", author_email='support@mehcode.com', maintainer='Bulat Gaifullin', From 1b3a5a038edabed09b07a8c80bb482f03d879205 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 14 Feb 2017 23:35:36 +0300 Subject: [PATCH 034/378] Configured auto deploy via travis --- .travis.yml | 37 +++++++++++++++++++++---------------- setup.py | 2 +- 2 files changed, 22 insertions(+), 17 deletions(-) diff --git a/.travis.yml b/.travis.yml index f0649bd5..1d799292 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,23 +2,28 @@ dist: trusty sudo: false language: python python: - - '2.7' - - '3.4' - - '3.5' - +- '2.7' +- '3.4' +- '3.5' addons: apt: packages: - - libssl-dev - - libxmlsec1 - - libxmlsec1-dev - - libxmlsec1-openssl - - libxslt1-dev - - pkg-config - + - libssl-dev + - libxmlsec1 + - libxmlsec1-dev + - libxmlsec1-openssl + - libxslt1-dev + - pkg-config install: - - travis_retry pip install -r requirements-test.txt - - travis_retry pip install -e "." - - pip list - -script: 'py.test tests' +- travis_retry pip install -r requirements-test.txt +- travis_retry pip install -e "." +- pip list +script: py.test tests +deploy: + provider: pypi + user: bgaifullin + password: + secure: sQrEP6/EXr2FHVL7ZSrP8VhqHAK7AptT+Ksi+GmtGLbTJxxVT7kVZQ5T8s8dHGyCfTUDdi5LGgHZPuPUvjzM+bcYqaU/4rG0oRSfmNG1w1Sgx0buSw7aUKXJZrJvNUW6I4ZDOs12T3oykDKfhi0Un8H4uTaJdczZDbWAm8vdmVQH/iyiDaE9bABFozBegXDxAtp7afMeLq89U6AoqTSZDNfFOaPvlFcXyD36+TwyBccOK6z4JD3R5bb84pMJrLFee1EgmfZsPGIRF9EigGbXZUeVV+2m3jBVlh1TVHB+3PXESSof+FUWLFFkGOnK7sKTSOWvbvK98hD+yNwQkymf3lw2bEn+0SonDCl7H4cIVpMSS0IN24EtNOTZ7uLH3Zbhxg8PyTjqqL2+WieFrC+3a1HAYaPgFnhs1U+n1gm4Zrk1hyOwZcYzWdtuOLThNEAATip1tsdQaeOD+qmChj8HG4TSv/g/QAe/7wUJqIIAOsO6VO4sN+yKcqK4U49+vbw8GgQedouvKLpq92E2v6jig5NNjpzf7nhvD8ugmpulOE1gDG6QSjb5DeZaGQDz1DsjlDET0LKlCcyWDKhyWnsTev5S3tq2ZTk3dV52ezMIlaDELG3VPSp5qV6WwIDg93DZIu/WzMf/hYoNgc5R4br8u9EWlzZGInZQNgLNH5afmr8= + on: + tags: true + branch: master diff --git a/setup.py b/setup.py index fb29aa56..a52f93d7 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ __name__ = "xmlsec" -__version__ = "1.0.2" +__version__ = os.getenv("TRAVIS_TAG", "1.0.2") # publish on tag is used __description__ = "Python bindings for the XML Security Library" From 2c37ab63169257b53ff2e771f8200db71d8a0f87 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 15 Feb 2017 00:23:56 +0300 Subject: [PATCH 035/378] Added missing files to sdist --- .travis.yml | 2 +- MANIFEST.in | 4 ++++ setup.cfg | 3 +++ setup.py | 2 +- 4 files changed, 9 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 1d799292..dbd008e1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ deploy: provider: pypi user: bgaifullin password: - secure: sQrEP6/EXr2FHVL7ZSrP8VhqHAK7AptT+Ksi+GmtGLbTJxxVT7kVZQ5T8s8dHGyCfTUDdi5LGgHZPuPUvjzM+bcYqaU/4rG0oRSfmNG1w1Sgx0buSw7aUKXJZrJvNUW6I4ZDOs12T3oykDKfhi0Un8H4uTaJdczZDbWAm8vdmVQH/iyiDaE9bABFozBegXDxAtp7afMeLq89U6AoqTSZDNfFOaPvlFcXyD36+TwyBccOK6z4JD3R5bb84pMJrLFee1EgmfZsPGIRF9EigGbXZUeVV+2m3jBVlh1TVHB+3PXESSof+FUWLFFkGOnK7sKTSOWvbvK98hD+yNwQkymf3lw2bEn+0SonDCl7H4cIVpMSS0IN24EtNOTZ7uLH3Zbhxg8PyTjqqL2+WieFrC+3a1HAYaPgFnhs1U+n1gm4Zrk1hyOwZcYzWdtuOLThNEAATip1tsdQaeOD+qmChj8HG4TSv/g/QAe/7wUJqIIAOsO6VO4sN+yKcqK4U49+vbw8GgQedouvKLpq92E2v6jig5NNjpzf7nhvD8ugmpulOE1gDG6QSjb5DeZaGQDz1DsjlDET0LKlCcyWDKhyWnsTev5S3tq2ZTk3dV52ezMIlaDELG3VPSp5qV6WwIDg93DZIu/WzMf/hYoNgc5R4br8u9EWlzZGInZQNgLNH5afmr8= + secure: wuWADHAmAz2e2wMMVadhDXh5UMqtYLM7NjzjT4LVojPzbI+04BHFjmUVDEe3nOtxiEv/oJuumutb24MNMppSRklmofy/jqyDwEEPwsNJWvLi8eK60AohAhmP5rU1Vp5B6azotWnDiVApL18t9+nJqL+6nEQ5dcQeu0jtskiC5EOaIMgB12+HHfV9QUHYsQp9t+4LMsM8TaIogom3DSMUaKTRHdWbcmHgmYF3JJTNPDyUkND8zr1bwezf/jb9ytRVzo/mQh0tsHQF80CdkC9Cu3rXxgnE0RUrU9gC2Nwyj4UZQOxhXXQpd55HEGE00jUscaiDCc6D4Y4NGZ2gu1l4lx2z3UyvV3YdaZMPg8FSCJ1Z6TuwDYAZl3WdIvidiDKU1Pj/YyP8RAMmNhmLpgZNsK9iQ3o9wNFgr0w4rutg1vJUVOgu5nEBVBqERX8YXIsoq7eSMIdJxiVA6sralxJLxGsmNhtxpxgr0UJKx12tnJCgZnDtquwObaPzeEoAkqWsxu5fDyxGRlB4UCMn2ZckdWkjRpjymiScgVWM+3N9x6pwD+9/EsR6N4S1zVIghjGmEkOm5yeiQr11T9ZQjDtFA7sap02a9d4jmxEk6EZW4KoBWTgFOs9/qb3YH79PGNVok/HjuctLLl/udVkD8JSYPUjCGSx08kdr1TCGTJSRGUQ= on: tags: true branch: master diff --git a/MANIFEST.in b/MANIFEST.in index a9042a51..88c976dc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1 +1,5 @@ include src/* +include README.md +include requirements*.txt +include LICENSE + diff --git a/setup.cfg b/setup.cfg index 87f9cdb9..7d05e4f0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,3 +1,6 @@ +[metadata] +description-file = README.md + [bdist_rpm] release = 1 build-requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel diff --git a/setup.py b/setup.py index a52f93d7..b03c957d 100644 --- a/setup.py +++ b/setup.py @@ -86,7 +86,7 @@ def patch_xmlsec(self): cmdclass={'build_ext': BuildExt}, setup_requires=parse_requirements('requirements.txt'), install_requires=parse_requirements('requirements.txt'), - author="Ryan Leckey", + author="Bulat Gaifullin", author_email='support@mehcode.com', maintainer='Bulat Gaifullin', maintainer_email='gaifullinbf@gmail.com', From 3d2be5f34bbceaa7977cdab249b574029f99d7fc Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 15 Feb 2017 00:36:39 +0300 Subject: [PATCH 036/378] Adjusted deploy via travis --- .travis.yml | 7 +++++-- setup.py | 2 +- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index dbd008e1..5555e652 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,8 @@ addons: - libxmlsec1-openssl - libxslt1-dev - pkg-config +before_install: +- sed -i "s/1.0.1/${TRAVIS_TAG:-1.0.1}/" setup.py install: - travis_retry pip install -r requirements-test.txt - travis_retry pip install -e "." @@ -23,7 +25,8 @@ deploy: provider: pypi user: bgaifullin password: - secure: wuWADHAmAz2e2wMMVadhDXh5UMqtYLM7NjzjT4LVojPzbI+04BHFjmUVDEe3nOtxiEv/oJuumutb24MNMppSRklmofy/jqyDwEEPwsNJWvLi8eK60AohAhmP5rU1Vp5B6azotWnDiVApL18t9+nJqL+6nEQ5dcQeu0jtskiC5EOaIMgB12+HHfV9QUHYsQp9t+4LMsM8TaIogom3DSMUaKTRHdWbcmHgmYF3JJTNPDyUkND8zr1bwezf/jb9ytRVzo/mQh0tsHQF80CdkC9Cu3rXxgnE0RUrU9gC2Nwyj4UZQOxhXXQpd55HEGE00jUscaiDCc6D4Y4NGZ2gu1l4lx2z3UyvV3YdaZMPg8FSCJ1Z6TuwDYAZl3WdIvidiDKU1Pj/YyP8RAMmNhmLpgZNsK9iQ3o9wNFgr0w4rutg1vJUVOgu5nEBVBqERX8YXIsoq7eSMIdJxiVA6sralxJLxGsmNhtxpxgr0UJKx12tnJCgZnDtquwObaPzeEoAkqWsxu5fDyxGRlB4UCMn2ZckdWkjRpjymiScgVWM+3N9x6pwD+9/EsR6N4S1zVIghjGmEkOm5yeiQr11T9ZQjDtFA7sap02a9d4jmxEk6EZW4KoBWTgFOs9/qb3YH79PGNVok/HjuctLLl/udVkD8JSYPUjCGSx08kdr1TCGTJSRGUQ= + secure: V7KMY7sTMk1zIEfJ4j9UiGWqwYRZHfeZ6qPt7lfRLF8QOE244/17/wYJRZhejk53YvRUMTK4Xh6tSOiwH9QRoI5vgcX5JJ5AQgI8xscidIDnxn9f/LOslp2LFLz+xM8XPmnqILclekA3T1RictbdKDuMFMY+MWgTSJu0QTOeUBM+LtbhqZKMr29T33EsVBdCjB77lw/2BqVlbo4TV9hxohbXth4OUd5wZdEMsDvrvySC1FUR4V/jzkcNrtxMnLjiDhvcapCfGwkEldCAI/liYulDQP3A3LZ7oeP04LvAO1XxL1Pq4VbnpENXYvtRL4mCIW8s8tDwYSsHi7633b6UIFVyjGegDboZCUDL1T86C54Sw8nLFSkNCBMXQOWDb1Sjilr80TYscaNXZl5BOI1XiOdtHRCwRkdpYr+UsfK3qgv8nsM+bCxTN4rDa/IfbcSWyM8OyLHbRQrXATgjXPwTCiURZVjsNEllUdSP0QH1jqrpapofbQV5nFVxohoF4UZVqJVYT6fljyyLPpjOgXWFU64m5L++y3hzYD1qeaCcm7TwhuF2k0IxT1j0Ze61MzufULHJ8BonGjBrgZG59Xk5JXKJWb+W+5DoodUK12hprBItH7EH7Ku3DE5QG+RHr18ivloMnApWggqBxdKb6bg6mXT0SekZbXmyTG7arEga4TA= on: tags: true - branch: master + distributions: sdist bdist_wheel + python: '3.5' diff --git a/setup.py b/setup.py index b03c957d..d783d227 100644 --- a/setup.py +++ b/setup.py @@ -8,7 +8,7 @@ __name__ = "xmlsec" -__version__ = os.getenv("TRAVIS_TAG", "1.0.2") # publish on tag is used +__version__ = "1.0.1" __description__ = "Python bindings for the XML Security Library" From a10092ed6eaf294569119c1c9220154b9a7a61e3 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 15 Feb 2017 01:44:49 +0300 Subject: [PATCH 037/378] Transformed README to rst format --- MANIFEST.in | 1 - README.md | 127 ---------------------------------------- README.rst | 166 ++++++++++++++++++++++++++++++++++++++++++++++++++++ setup.cfg | 2 +- 4 files changed, 167 insertions(+), 129 deletions(-) delete mode 100644 README.md create mode 100644 README.rst diff --git a/MANIFEST.in b/MANIFEST.in index 88c976dc..07ed1203 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,5 +1,4 @@ include src/* -include README.md include requirements*.txt include LICENSE diff --git a/README.md b/README.md deleted file mode 100644 index 24b177d6..00000000 --- a/README.md +++ /dev/null @@ -1,127 +0,0 @@ -# python-xmlsec -[![Build Status](https://travis-ci.org/mehcode/python-xmlsec.png?branch=master)](https://travis-ci.org/mehcode/python-xmlsec) -[![PyPi Version](https://img.shields.io/pypi/v/xmlsec.svg)](https://pypi.python.org/pypi/xmlsec) -![PyPi Downloads](https://img.shields.io/pypi/dm/xmlsec.svg) -> Python bindings for the XML Security Library. - -## Usage - -Check the [examples](https://github.com/mehcode/python-xmlsec/tree/master/tests/examples) to see various examples of signing and verifying using the library. - -## Requirements -- libxml2 >= 2.9.1 -- libxmlsec1 >= 1.2.14 - -## Install - -### Pre-Install - -#### Linux (Debian) - - ```sh - apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-opensssl - ``` - -Note: There is no required version of libxml2 for ubuntu precise, -so need to dowload and install it manually. -```sh -wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz -tar -xvf libxml2-2.9.1.tar.gz -cd libxml2-2.9.1 -./configure && make && make install -``` - -#### Linux (CentOS) - - ```sh - yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel - ``` - -#### Mac - - ```sh - brew install libxml2 libxmlsec1 - ``` - -### Automated - -1. **xmlsec** can be installed through `easy_install` or `pip`. - - ```sh - pip install xmlsec - ``` - -#### Mac - -If you get any fatal errors about missing .h files, update your C_INCLUDE_PATH environment variable to -include the appropriate files from the libxml2 and libxmlsec1 libraries. - -### Manual - -1. Clone the **xmlsec** repository to your local computer. - - ```sh - git clone git://github.com/mehcode/python-xmlsec.git - ``` - -2. Change into the **xmlsec** root directory. - - ```sh - cd /path/to/xmlsec - ``` - -3. Install the project and all its dependencies using `pip`. - - ```sh - pip install . - ``` - -## Contributing - -### Setting up your environment - -1. Follow steps 1 and 2 of the [manual installation instructions][]. - -[manual installation instructions]: #manual - -2. Initialize a virtual environment to develop in. - This is done so as to ensure every contributor is working with - close-to-identicial versions of packages. - - ```sh - mkvirtualenv xmlsec - ``` - - The `mkvirtualenv` command is available from `virtualenvwrapper` which - can be installed by following: http://virtualenvwrapper.readthedocs.org/en/latest/install.html#basic-installation - -3. Install **xmlsec** in development mode with testing enabled. - This will download all dependencies required for running the unit tests. - - ```sh - pip install -r requirements-test.txt - pip install -e "." - ``` - -### Running the test suite - -1. [Set up your environment](#setting-up-your-environment). - -2. Run the unit tests. - - ```sh - py.test tests - ``` - -## Versions of python -The following versions of python is supported - - python2.7 - - python3.4 - - python3.5 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) - - python3.6 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) - -## License - -Unless otherwise noted, all files contained within this project are liensed under the MIT opensource license. See the included file LICENSE or visit [opensource.org][] for more information. - -[opensource.org]: http://opensource.org/licenses/MIT diff --git a/README.rst b/README.rst new file mode 100644 index 00000000..9fa75dca --- /dev/null +++ b/README.rst @@ -0,0 +1,166 @@ +python-xmlsec +============= + +.. image:: https://travis-ci.org/mehcode/python-xmlsec.png?branch=master + :target: https://travis-ci.org/mehcode/python-xmlsec +.. image:: https://img.shields.io/pypi/v/xmlsec.svg + :target: https://pypi.python.org/pypi/xmlsec +.. image:: https://img.shields.io/pypi/dm/xmlsec.svg + :target: https://pypi.python.org/pypi/xmlsec + + +Python bindings for the XML Security Library. + +****** +Usage +****** + +Check the `examples `_ to see various examples of signing and verifying using the library. + +************ +Requirements +************ +- libxml2 >= 2.9.1 +- libxmlsec1 >= 1.2.14 + +******* +Install +******* + +Pre-Install +----------- + +Linux (Debian) +^^^^^^^^^^^^^^ + +.. code-block:: bash + + apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-opensssl + + +Note: There is no required version of libxml2 for ubuntu precise, +so need to dowload and install it manually. + +.. code-block:: bash + + wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz + tar -xvf libxml2-2.9.1.tar.gz + cd libxml2-2.9.1 + ./configure && make && make install + + +Linux (CentOS) +^^^^^^^^^^^^^^ + +.. code-block:: bash + + yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel + + +Mac +^^^ + +.. code-block:: bash + + brew install libxml2 libxmlsec1 + + +Automated +--------- +1. **xmlsec** can be installed through `easy_install` or `pip`. + +.. code-block:: bash + + pip install xmlsec + + +Mac +^^^ + +If you get any fatal errors about missing .h files, update your C_INCLUDE_PATH environment variable to +include the appropriate files from the libxml2 and libxmlsec1 libraries. + +Manual +------ + +1. Clone the **xmlsec** repository to your local computer. + +.. code-block:: bash + + git clone git://github.com/mehcode/python-xmlsec.git + +2. Change into the **xmlsec** root directory. + +.. code-block:: bash + + cd /path/to/xmlsec + + +3. Install the project and all its dependencies using `pip`. + +.. code-block:: bash + + pip install . + + +************ +Contributing +************ + +Setting up your environment +--------------------------- + +1. Follow steps 1 and 2 of the [manual installation instructions][]. + +[manual installation instructions]: #manual + +2. Initialize a virtual environment to develop in. + This is done so as to ensure every contributor is working with + close-to-identicial versions of packages. + +.. code-block:: bash + + mkvirtualenv xmlsec + + + The `mkvirtualenv` command is available from `virtualenvwrapper` which + can be installed by following: http://virtualenvwrapper.readthedocs.org/en/latest/install.html#basic-installation + +3. Install **xmlsec** in development mode with testing enabled. + This will download all dependencies required for running the unit tests. + +.. code-block:: bash + + pip install -r requirements-test.txt + pip install -e "." + + +Running the test suite +---------------------- + +1. [Set up your environment](#setting-up-your-environment). + +2. Run the unit tests. + +.. code-block:: bash + + py.test tests + + +****************** +Versions of python +****************** + +The following versions of python is supported: + + - python2.7 + - python3.4 + - python3.5 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + - python3.6 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + +******* +License +******* + +Unless otherwise noted, all files contained within this project are liensed under the MIT opensource license. +See the included file LICENSE or visit `opensource.org `_ for more information. diff --git a/setup.cfg b/setup.cfg index 7d05e4f0..28b996e9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [metadata] -description-file = README.md +description-file = README.rst [bdist_rpm] release = 1 From e68b4914a07a9b3ac8580df8c6308c772ecc4060 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 17 Feb 2017 11:58:52 +0300 Subject: [PATCH 038/378] Fixed compilation error with xmlsec > 1.2.20 #46 --- src/constants.c | 2 ++ src/platform.h | 6 ++++++ 2 files changed, 8 insertions(+) diff --git a/src/constants.c b/src/constants.c index b5d7b8e4..4c890729 100644 --- a/src/constants.c +++ b/src/constants.c @@ -284,7 +284,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_NS_CONSTANT(Ns, "BASE"); PYXMLSEC_ADD_NS_CONSTANT(DSigNs, "DS"); PYXMLSEC_ADD_NS_CONSTANT(EncNs, "ENC"); +#ifndef XMLSEC_NO_XKMS PYXMLSEC_ADD_NS_CONSTANT(XkmsNs, "XKMS"); +#endif PYXMLSEC_ADD_NS_CONSTANT(XPathNs, "XPATH"); PYXMLSEC_ADD_NS_CONSTANT(XPath2Ns, "XPATH2"); PYXMLSEC_ADD_NS_CONSTANT(XPointerNs, "XPOINTER"); diff --git a/src/platform.h b/src/platform.h index bde45cee..eae902b9 100644 --- a/src/platform.h +++ b/src/platform.h @@ -21,6 +21,12 @@ #define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 8) | (XMLSEC_VERSION_MINOR << 4) | (XMLSEC_VERSION_SUBMINOR)) +// XKMS support was removed in version 1.2.21 +// https://mail.gnome.org/archives/commits-list/2015-February/msg10555.html +#if XMLSEC_VERSION_HEX > 0x134 +#define XMLSEC_NO_XKMS 1 +#endif + #define XSTR(c) (const xmlChar*)(c) #if PY_VERSION_HEX < 0x02050000 && !defined(PY_SSIZE_T_MIN) From d155dc1d04a486651df551b4ad1c059a0f85fcd7 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 7 Mar 2017 17:04:06 +0300 Subject: [PATCH 039/378] Fixed initialization with dynamic crypto library #48 --- src/main.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 26159089..a05700a7 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,7 @@ static int PyXmlSec_Init(void) { } #ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING - if (xmlSecCryptoDLLoadLibrary(NULL) < 0) { + if (xmlSecCryptoDLLoadLibrary((const xmlChar*) STRINGIFY(XMLSEC_CRYPTO)) < 0) { PyXmlSec_SetLastError("cannot load crypto library for xmlsec."); PyXmlSec_Free(_FREE_XMLSEC); return -1; From a9d7f1c709c134f8bacd7e791c6158bd952fcfcb Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 7 Mar 2017 18:38:07 +0300 Subject: [PATCH 040/378] Added section "issue reporting" --- README.rst | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.rst b/README.rst index 9fa75dca..d285475d 100644 --- a/README.rst +++ b/README.rst @@ -146,6 +146,19 @@ Running the test suite py.test tests +Reporting a issue +----------------- +Please attach the output of following information: +version of python-xmlsec +version of libxmlsec1 +version of libxml2 + +output from command: + +.. code-block:: bash + + pkg-config --cflags xmlsec1 + ****************** Versions of python From 961b0bd396d4b169915c5843f76aa6d325f0e8ae Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 10 Mar 2017 20:41:50 +0300 Subject: [PATCH 041/378] fixed loading crypto library for xmlsec >1.2.21 #50 --- setup.py | 21 +++++++++++++++++---- src/main.c | 10 ++++++++-- 2 files changed, 25 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index d783d227..0e8c6c73 100644 --- a/setup.py +++ b/setup.py @@ -21,18 +21,29 @@ def is_debug(): if is_debug(): - macroses.append(("PYXMLSEC_ENABLE_DEBUG", 1)) + macroses.append(("PYXMLSEC_ENABLE_DEBUG", "1")) cflags.extend(["-Wall", "-O0"]) else: cflags.extend(["-Os"]) -def add_to_list(target, up): +# values which requires escaping +require_escape = {"XMLSEC_CRYPTO"} + + +def add_to_list(target, up, need_to_escape=None): if up is None: return target value = set(target) - value.update(up) + if need_to_escape: + for x in up: + if x[0] in need_to_escape: + value.add((x[0], '"{0}"'.format(x[1]))) + else: + value.add(x) + else: + value.update(up) target[:] = list(value) @@ -61,10 +72,12 @@ def patch_xmlsec(self): ext = self.ext_map[__name__] config = pkgconfig.parse("xmlsec1") + # need to escape XMLSEC_CRYPTO # added build flags from pkg-config - for item in ('define_macros', 'libraries', 'library_dirs', 'include_dirs'): + for item in ('libraries', 'library_dirs', 'include_dirs'): add_to_list(getattr(ext, item), config.get(item)) + add_to_list(ext.define_macros, config.get('define_macros'), {"XMLSEC_CRYPTO"}) add_to_list(ext.include_dirs, lxml.get_include()) diff --git a/src/main.c b/src/main.c index a05700a7..26842c26 100644 --- a/src/main.c +++ b/src/main.c @@ -46,7 +46,14 @@ static int PyXmlSec_Init(void) { } #ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING - if (xmlSecCryptoDLLoadLibrary((const xmlChar*) STRINGIFY(XMLSEC_CRYPTO)) < 0) { +#if XMLSEC_VERSION_HEX > 308 + // xmlSecGetDefaultCrypto was introduced in version 1.2.21 + const xmlChar* cryptoLib = xmlSecGetDefaultCrypto(); +#else + const xmlChar* cryptoLib = (const xmlChar*) XMLSEC_CRYPTO; +#endif + PYXMLSEC_DEBUGF("dynamic crypto library: %s", cryptoLib); + if (xmlSecCryptoDLLoadLibrary(cryptoLib) < 0) { PyXmlSec_SetLastError("cannot load crypto library for xmlsec."); PyXmlSec_Free(_FREE_XMLSEC); return -1; @@ -240,6 +247,5 @@ PYENTRY_FUNC_NAME(void) PY_MOD_RETURN(module); ON_FAIL: - Py_DECREF(module); PY_MOD_RETURN(NULL); } From f53d3c44544c653be131623831b54c32653bf786 Mon Sep 17 00:00:00 2001 From: Stephen Burrows Date: Thu, 16 Mar 2017 09:59:12 -0700 Subject: [PATCH 042/378] Removed extra s from openssl `opensssl` -> `openssl` --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index d285475d..53d427f5 100644 --- a/README.rst +++ b/README.rst @@ -35,7 +35,7 @@ Linux (Debian) .. code-block:: bash - apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-opensssl + apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl Note: There is no required version of libxml2 for ubuntu precise, From 0af398fc66f121f900dcdfeae8c336c0f5d3cc46 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Tue, 11 Apr 2017 14:02:51 -0700 Subject: [PATCH 043/378] Add PyPi encrypted credentials for Travis --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5555e652..3bf39ea5 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,10 +23,10 @@ install: script: py.test tests deploy: provider: pypi - user: bgaifullin - password: - secure: V7KMY7sTMk1zIEfJ4j9UiGWqwYRZHfeZ6qPt7lfRLF8QOE244/17/wYJRZhejk53YvRUMTK4Xh6tSOiwH9QRoI5vgcX5JJ5AQgI8xscidIDnxn9f/LOslp2LFLz+xM8XPmnqILclekA3T1RictbdKDuMFMY+MWgTSJu0QTOeUBM+LtbhqZKMr29T33EsVBdCjB77lw/2BqVlbo4TV9hxohbXth4OUd5wZdEMsDvrvySC1FUR4V/jzkcNrtxMnLjiDhvcapCfGwkEldCAI/liYulDQP3A3LZ7oeP04LvAO1XxL1Pq4VbnpENXYvtRL4mCIW8s8tDwYSsHi7633b6UIFVyjGegDboZCUDL1T86C54Sw8nLFSkNCBMXQOWDb1Sjilr80TYscaNXZl5BOI1XiOdtHRCwRkdpYr+UsfK3qgv8nsM+bCxTN4rDa/IfbcSWyM8OyLHbRQrXATgjXPwTCiURZVjsNEllUdSP0QH1jqrpapofbQV5nFVxohoF4UZVqJVYT6fljyyLPpjOgXWFU64m5L++y3hzYD1qeaCcm7TwhuF2k0IxT1j0Ze61MzufULHJ8BonGjBrgZG59Xk5JXKJWb+W+5DoodUK12hprBItH7EH7Ku3DE5QG+RHr18ivloMnApWggqBxdKb6bg6mXT0SekZbXmyTG7arEga4TA= + user: mehcode on: tags: true distributions: sdist bdist_wheel python: '3.5' + password: + secure: Gq9Ut9FATKUSVoaTTSeecN8kWxRQjTe4K+gK/gKuRJqWzYPOG9AhCq2Nxd3rwlWedPWpfoQwmlCuCma68npVQZnsJqyNYmEUBp4xjgDXOR12q2jDlgT0SH5V23ysJydA+c5QuHGXz7INxBTSwCjD+xBe2WXRxp9RJoi8kLloFt0= From acba274436db92704796deb84d7af3579e59740a Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 17 Mar 2017 10:26:11 +0300 Subject: [PATCH 044/378] switched to beta status --- .travis.yml | 1 + setup.py | 6 +----- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3bf39ea5..c9714d89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -22,6 +22,7 @@ install: - pip list script: py.test tests deploy: + skip_cleanup: true provider: pypi user: mehcode on: diff --git a/setup.py b/setup.py index 0e8c6c73..65ff5e6b 100644 --- a/setup.py +++ b/setup.py @@ -27,10 +27,6 @@ def is_debug(): cflags.extend(["-Os"]) -# values which requires escaping -require_escape = {"XMLSEC_CRYPTO"} - - def add_to_list(target, up, need_to_escape=None): if up is None: return target @@ -108,7 +104,7 @@ def patch_xmlsec(self): license='MIT', keywords=["xmlsec"], classifiers=[ - 'Development Status :: 3 - Alpha', + 'Development Status :: 4 - Beta', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', From baa24e23a42d800485a7933d622ef88a4d56d67d Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sun, 14 May 2017 22:35:15 +0300 Subject: [PATCH 045/378] fixed xmlsec.tree module initialization --- src/tree.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tree.c b/src/tree.c index b2fc4ddc..788bc546 100644 --- a/src/tree.c +++ b/src/tree.c @@ -212,7 +212,7 @@ int PyXmlSec_TreeModule_Init(PyObject* package) { #ifdef PY3K PyObject* tree = PyModule_Create(&PyXmlSec_TreeModule); #else - PyObject* tree = Py_InitModule3(STRINGIFY(MODULE_NAME) ".template", PyXmlSec_TreeMethods, PYXMLSEC_TREE_DOC); + PyObject* tree = Py_InitModule3(STRINGIFY(MODULE_NAME) ".tree", PyXmlSec_TreeMethods, PYXMLSEC_TREE_DOC); Py_XINCREF(tree); #endif From 955961f8ef78f513a8e93022f2fb4cdd38517bc5 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Mon, 15 May 2017 02:25:21 +0300 Subject: [PATCH 046/378] Added documentation #45 --- .travis.yml | 7 +- README.rst | 2 +- doc/Makefile | 20 ++++ doc/source/api.rst | 13 +++ doc/source/conf.py | 156 +++++++++++++++++++++++++++++++ doc/source/examples.rst | 116 +++++++++++++++++++++++ doc/source/index.rst | 28 ++++++ doc/source/install.rst | 42 +++++++++ doc/source/modules/constants.rst | 147 +++++++++++++++++++++++++++++ doc/source/modules/template.rst | 9 ++ doc/source/modules/tree.rst | 9 ++ doc/source/modules/xmlsec.rst | 9 ++ setup.cfg | 8 ++ src/ds.c | 39 ++++++-- src/enc.c | 22 +++-- src/keys.c | 61 +++++++++--- src/main.c | 21 +++-- src/template.c | 101 ++++++++++++++++---- src/tree.c | 22 ++++- 19 files changed, 767 insertions(+), 65 deletions(-) create mode 100644 doc/Makefile create mode 100644 doc/source/api.rst create mode 100644 doc/source/conf.py create mode 100644 doc/source/examples.rst create mode 100644 doc/source/index.rst create mode 100644 doc/source/install.rst create mode 100644 doc/source/modules/constants.rst create mode 100644 doc/source/modules/template.rst create mode 100644 doc/source/modules/tree.rst create mode 100644 doc/source/modules/xmlsec.rst diff --git a/.travis.yml b/.travis.yml index c9714d89..6f7f4f5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -21,6 +21,11 @@ install: - travis_retry pip install -e "." - pip list script: py.test tests + +before_deploy: + - travis_retry pip install Sphinx + - python setup.py build_sphinx + deploy: skip_cleanup: true provider: pypi @@ -28,6 +33,6 @@ deploy: on: tags: true distributions: sdist bdist_wheel - python: '3.5' + python: '2.7' password: secure: Gq9Ut9FATKUSVoaTTSeecN8kWxRQjTe4K+gK/gKuRJqWzYPOG9AhCq2Nxd3rwlWedPWpfoQwmlCuCma68npVQZnsJqyNYmEUBp4xjgDXOR12q2jDlgT0SH5V23ysJydA+c5QuHGXz7INxBTSwCjD+xBe2WXRxp9RJoi8kLloFt0= diff --git a/README.rst b/README.rst index 53d427f5..ccf41112 100644 --- a/README.rst +++ b/README.rst @@ -39,7 +39,7 @@ Linux (Debian) Note: There is no required version of libxml2 for ubuntu precise, -so need to dowload and install it manually. +so need to download and install it manually. .. code-block:: bash diff --git a/doc/Makefile b/doc/Makefile new file mode 100644 index 00000000..119469fb --- /dev/null +++ b/doc/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = sphinx-build +SPHINXPROJ = python-xmlsec +SOURCEDIR = source +BUILDDIR = build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file diff --git a/doc/source/api.rst b/doc/source/api.rst new file mode 100644 index 00000000..d142f3bd --- /dev/null +++ b/doc/source/api.rst @@ -0,0 +1,13 @@ +API Reference +============= + +.. toctree:: + :maxdepth: 1 + + modules/xmlsec + modules/constants + modules/template + modules/tree + + +:ref:`contents` diff --git a/doc/source/conf.py b/doc/source/conf.py new file mode 100644 index 00000000..0bdbb022 --- /dev/null +++ b/doc/source/conf.py @@ -0,0 +1,156 @@ +# -*- coding: utf-8 -*- +# +# python-xmlsec documentation build configuration file, created by +# sphinx-quickstart on Fri Mar 17 10:30:14 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another directory, +# add these directories to sys.path here. If the directory is relative to the +# documentation root, use os.path.abspath to make it absolute, like shown here. +# +import os +# import sys +# sys.path.insert(0, os.path.abspath('.')) + + +# -- General configuration ------------------------------------------------ + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom +# ones. +extensions = ['sphinx.ext.autodoc', + 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'python-xmlsec' +copyright = u'2017, Bulat Gaifullin ' +author = u'Bulat Gaifullin ' + +# The version info for the project you're documenting, acts as replacement for +# |version| and |release|, also used in various other places throughout the +# built documents. +# +# The short X.Y version. +version = os.getenv("TRAVIS_TAG", '1.0.1') +# The full version, including alpha/beta/rc tags. +release = version + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = [] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ---------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'nature' + +# Theme options are theme-specific and customize the look and feel of a theme +# further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = [] + + +# -- Options for HTMLHelp output ------------------------------------------ + +# Output file base name for HTML help builder. +htmlhelp_basename = 'python-xmlsecdoc' + + +# -- Options for LaTeX output --------------------------------------------- + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, +# author, documentclass [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'python-xmlsec.tex', u'python-xmlsec Documentation', + u'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}', 'manual'), +] + + +# -- Options for manual page output --------------------------------------- + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'python-xmlsec', u'python-xmlsec Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ------------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'python-xmlsec', u'python-xmlsec Documentation', + author, 'python-xmlsec', 'One line description of project.', + 'Miscellaneous'), +] + +autodoc_member_order = 'groupwise' diff --git a/doc/source/examples.rst b/doc/source/examples.rst new file mode 100644 index 00000000..e0427d75 --- /dev/null +++ b/doc/source/examples.rst @@ -0,0 +1,116 @@ +Examples +======== + +Decrypt +------- +.. code:: python + + from lxml import etree + import xmlsec + + manager = xmlsec.KeysManager() + key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) + manager.add_key(key) + enc_ctx = xmlsec.EncryptionContext(manager) + root = etree.parse("enc1-res.xml").getroot() + enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.constants.EncNs) + decrypted = enc_ctx.decrypt(enc_data) + print(etree.tostring(decrypted)) + + +Encrypt +------- +.. code:: python + + from lxml import etree + import xmlsec + + manager = xmlsec.KeysManager() + key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None) + manager.add_key(key) + template = etree.parse('enc1-doc.xml').getroot() + enc_data = xmlsec.template.encrypted_data_create( + template, xmlsec.constants.TransformAes128Cbc, type=xmlsec.constants.TypeEncContent, ns="xenc") + + xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) + key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) + xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) + data = template.find('./Data') + + # Encryption + enc_ctx = xmlsec.EncryptionContext(manager) + enc_ctx.key = xmlsec.Key.generate(xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession) + enc_datsa = enc_ctx.encrypt_xml(enc_data, data) + enc_method = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) + key_info = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs) + enc_method = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) + cipher_value = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs) + print(etree.tostring(cipher_value)) + + +Sign +---- +.. code:: python + + from lxml import etree + import xmlsec + + template = etree.parse('sign1-tmpl.xml').getroot() + + signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) + ctx = xmlsec.SignatureContext() + key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) + ctx.key = key + ctx.sign(signature_node) + print(etree.tostring(template)) + + +Sign-Binary +----------- +.. code:: python + + from lxml import etree + import xmlsec + + ctx = xmlsec.SignatureContext() + key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) + ctx.key = key + data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' + sign = ctx.sign_binary(data, xmlsec.constants.TransformRsaSha1) + print(sign) + + + +Verify +------ +.. code:: python + + from lxml import etree + import xmlsec + + template = etree.parse('sign1-res.xml').getroot() + xmlsec.tree.add_ids(template, ["ID"]) + signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) + # Create a digital signature context (no key manager is needed). + ctx = xmlsec.SignatureContext() + key = xmlsec.Key.from_file('rsapub.pem', xmlsec.constants.KeyDataFormatPem) + # Set the key on the context. + ctx.key = key + ctx.verify(signature_node) + + +Verify-Binary +------------- +.. code:: python + + from lxml import etree + import xmlsec + + ctx = xmlsec.SignatureContext() + key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) + ctx.key = key + + data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' + sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" + ctx.verify_binary(data, xmlsec.constants.TransformRsaSha1, sign) diff --git a/doc/source/index.rst b/doc/source/index.rst new file mode 100644 index 00000000..6c3d313f --- /dev/null +++ b/doc/source/index.rst @@ -0,0 +1,28 @@ +.. python-xmlsec documentation master file, created by + sphinx-quickstart on Fri Mar 17 10:30:14 2017. + You can adapt this file completely to your liking, but it should at least + contain the root `toctree` directive. + +Welcome to python-xmlsec's documentation! +========================================= + +Python bindings for the XML Security Library. + +.. _contents: + +Table of contents +================= + +.. toctree:: + :maxdepth: 2 + + install + api + examples + +Indices and tables +================== + +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/doc/source/install.rst b/doc/source/install.rst new file mode 100644 index 00000000..43987710 --- /dev/null +++ b/doc/source/install.rst @@ -0,0 +1,42 @@ +Install +----------- + +Linux (Debian) +^^^^^^^^^^^^^^ + +.. code-block:: bash + + apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl + pip install xmlsec + + +Note: There is no required version of libxml2 for ubuntu precise, +so need to download and install it manually. + +.. code-block:: bash + + wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz + tar -xvf libxml2-2.9.1.tar.gz + cd libxml2-2.9.1 + ./configure && make && make install + + +Linux (CentOS) +^^^^^^^^^^^^^^ + +.. code-block:: bash + + yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel + pip install xmlsec + + +Mac +^^^ + +.. code-block:: bash + + xcode-select --install + brew upgrade + brew install libxml2 libxmlsec1 + pip install xmlsec + diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst new file mode 100644 index 00000000..c69ef359 --- /dev/null +++ b/doc/source/modules/constants.rst @@ -0,0 +1,147 @@ +xmlsec.constants +---------------- + +Various constants used by the library + +EncryptionType +************** +- *TypeEncContent* - http://www.w3.org/2001/04/xmlenc#Content +- *TypeEncElement* - http://www.w3.org/2001/04/xmlenc#Element + +KeyData +******* +- *KeyDataName* - The processing class. +- *KeyDataValue* - The processing class. +- *KeyDataRetrievalMethod* - The processing class. +- *KeyDataEncryptedKey* - The processing class. +- *KeyDataAes* - The AES key klass. +- *KeyDataDes* - The DES key klass. +- *KeyDataDsa* - The DSA key klass. +- *KeyDataEcdsa* - The ECDSA key klass. +- *KeyDataHmac* - The DHMAC key klass. +- *KeyDataRsa* - The RSA key klass. +- *KeyDataX509* - The X509 data klass. +- *KeyDataRawX509Cert* - The raw X509 certificate klass. + +KeyDataFormat +************* +- *KeyDataFormatUnknown* - the key data format is unknown. +- *KeyDataFormatBinary* - the binary key data. +- *KeyDataFormatPem* - the PEM key data (cert or public/private key). +- *KeyDataFormatDer* - the DER key data (cert or public/private key). +- *KeyDataFormatPkcs8Pem* - the PKCS8 PEM private key. +- *KeyDataFormatPkcs8Der* - the PKCS8 DER private key. +- *KeyDataFormatPkcs12* - the PKCS12 format (bag of keys and certs) +- *KeyDataFormatCertPem* - the PEM cert. +- *KeyDataFormatCertDer* - the DER cert. + +KeyDataType +*********** +- *KeyDataTypeUnknown* - The key data type is unknown +- *KeyDataTypeNone* - The key data type is unknown +- *KeyDataTypePublic* - The key data contain a public key. +- *KeyDataTypePrivate* - The key data contain a private key. +- *KeyDataTypeSymmetric* - The key data contain a symmetric key. +- *KeyDataTypeSession* - The key data contain session key (one time key, not stored in keys manager). +- *KeyDataTypePermanent* - The key data contain permanent key (stored in keys manager). +- *KeyDataTypeTrusted* - The key data is trusted. +- *KeyDataTypeAny* - The key data is trusted. + +Namespaces +********** + +- *Ns* - http://www.aleksey.com/xmlsec/2002 +- *DSigNs* - http://www.w3.org/2000/09/xmldsig# +- *EncNs* - http://www.w3.org/2001/04/xmlenc# +- *XPathNs* - http://www.w3.org/TR/1999/REC-xpath-19991116 +- *XPath2Ns* - http://www.w3.org/2002/06/xmldsig-filter2 +- *XPointerNs* - http://www.w3.org/2001/04/xmldsig-more/xptr +- *Soap11Ns* - http://schemas.xmlsoap.org/soap/envelope/ +- *Soap12Ns* - http://www.w3.org/2002/06/soap-envelope + +Nodes +***** +- *NodeSignature* - Signature +- *NodeSignedInfo* - SignedInfo +- *NodeCanonicalizationMethod* - CanonicalizationMethod +- *NodeSignatureMethod* - SignatureMethod +- *NodeSignatureValue* - SignatureValue +- *NodeSignatureProperties* - SignatureProperties +- *NodeDigestMethod* - DigestMethod +- *NodeDigestValue* - DigestValue +- *NodeObject* - Object +- *NodeManifest* - Manifest +- *NodeEncryptedData* - EncryptedData +- *NodeEncryptionMethod* - EncryptionMethod +- *NodeEncryptionProperties* - EncryptionProperties +- *NodeEncryptionProperty* - EncryptionProperty +- *NodeCipherData* - CipherData +- *NodeCipherValue* - CipherValue +- *NodeCipherReference* - CipherReference +- *NodeReferenceList* - ReferenceList +- *NodeDataReference* - DataReference +- *NodeKeyReference* - KeyReference +- *NodeKeyInfo* - KeyInfo + +Transforms +********** + +- *TransformUsageUnknown* - Transforms usage is unknown or undefined. +- *TransformUsageDSigTransform* - Transform could be used in . +- *TransformUsageC14NMethod* - Transform could be used in . +- *TransformUsageDigestMethod* - Transform could be used in . +- *TransformUsageSignatureMethod* - Transform could be used in . +- *TransformUsageEncryptionMethod* - Transform could be used in . +- *TransformUsageAny* - Transform could be used for operation. +- *TransformInclC14N* - The regular (inclusive) C14N without comments transform klass. +- *TransformInclC14NWithComments* - The regular (inclusive) C14N with comments transform klass. +- *TransformInclC14N11* - The regular (inclusive) C14N 1.1 without comments transform klass. +- *TransformInclC14N11WithComments* - The regular (inclusive) C14N 1.1 with comments transform klass. +- *TransformExclC14N* - The exclusive C14N without comments transform klass. +- *TransformExclC14NWithComments* - The exclusive C14N with comments transform klass. +- *TransformEnveloped* - The "enveloped" transform klass. +- *TransformXPath* - The XPath transform klass. +- *TransformXPath2* - The XPath2 transform klass. +- *TransformXPointer* - The XPointer transform klass. +- *TransformXslt* - The XSLT transform klass. +- *TransformRemoveXmlTagsC14N* - The "remove all xml tags" transform klass (used before base64 transforms). +- *TransformVisa3DHack* - Selects node subtree by given node id string. The only reason why we need this is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows invalid XPointer expressions in the URI attribute. Since we couldn't evaluate such expressions thru XPath/XPointer engine, we need to have this hack here. +- *TransformAes128Cbc* - The AES128 CBC cipher transform klass. +- *TransformAes192Cbc* - The AES192 CBC cipher transform klass. +- *TransformAes256Cbc* - The AES256 CBC cipher transform klass. +- *TransformKWAes128* - The AES 128 key wrap transform klass. +- *TransformKWAes192* - The AES 192 key wrap transform klass. +- *TransformKWAes256* - The AES 256 key wrap transform klass. +- *TransformDes3Cbc* - The Triple DES encryption transform klass. +- *TransformKWDes3* - The DES3 CBC cipher transform klass. +- *TransformDsaSha1* - The DSA-SHA1 signature transform klass. +- *TransformEcdsaSha1* - The ECDSA-SHA1 signature transform klass. +- *TransformEcdsaSha224* - The ECDSA-SHA224 signature transform klass. +- *TransformEcdsaSha256* - The ECDSA-SHA256 signature transform klass. +- *TransformEcdsaSha384* - The ECDS-SHA384 signature transform klass. +- *TransformEcdsaSha512* - The ECDSA-SHA512 signature transform klass. +- *TransformHmacMd5* - The HMAC with MD5 signature transform klass. +- *TransformHmacRipemd160* - The HMAC with RipeMD160 signature transform klass. +- *TransformHmacSha1* - The HMAC with SHA1 signature transform klass. +- *TransformHmacSha224* - The HMAC with SHA224 signature transform klass. +- *TransformHmacSha256* - The HMAC with SHA256 signature transform klass. +- *TransformHmacSha384* - The HMAC with SHA384 signature transform klass. +- *TransformHmacSha512* - The HMAC with SHA512 signature transform klass. +- *TransformRsaMd5* - The RSA-MD5 signature transform klass. +- *TransformRsaRipemd160* - The RSA-RIPEMD160 signature transform klass. +- *TransformRsaSha1* - The RSA-SHA1 signature transform klass. +- *TransformRsaSha224* - The RSA-SHA224 signature transform klass. +- *TransformRsaSha256* - The RSA-SHA256 signature transform klass. +- *TransformRsaSha384* - The RSA-SHA384 signature transform klass. +- *TransformRsaSha512* - The RSA-SHA512 signature transform klass. +- *TransformRsaPkcs1* - The RSA PKCS1 key transport transform klass. +- *TransformRsaOaep* - The RSA PKCS1 key transport transform klass. +- *TransformMd5* - The MD5 digest transform klass. +- *TransformRipemd160* - The RIPEMD160 digest transform klass. +- *TransformSha1* - The SHA1 digest transform klass. +- *TransformSha224* - The SHA224 digest transform klass. +- *TransformSha256* - The SHA256 digest transform klass. +- *TransformSha384* - The SHA384 digest transform klass. +- *TransformSha512* - The SHA512 digest transform klass. + +:ref:`contents` diff --git a/doc/source/modules/template.rst b/doc/source/modules/template.rst new file mode 100644 index 00000000..c1e4b762 --- /dev/null +++ b/doc/source/modules/template.rst @@ -0,0 +1,9 @@ +xmlsec.template +--------------- + +.. automodule:: xmlsec.template + :members: + :undoc-members: + + +:ref:`contents` diff --git a/doc/source/modules/tree.rst b/doc/source/modules/tree.rst new file mode 100644 index 00000000..0dd70ea4 --- /dev/null +++ b/doc/source/modules/tree.rst @@ -0,0 +1,9 @@ +xmlsec.tree +----------- + +.. automodule:: xmlsec.tree + :members: + :undoc-members: + + +:ref:`contents` diff --git a/doc/source/modules/xmlsec.rst b/doc/source/modules/xmlsec.rst new file mode 100644 index 00000000..35a16339 --- /dev/null +++ b/doc/source/modules/xmlsec.rst @@ -0,0 +1,9 @@ +xmlsec +------ + +.. automodule:: xmlsec + :members: + :undoc-members: + + +:ref:`contents` diff --git a/setup.cfg b/setup.cfg index 28b996e9..3b305822 100644 --- a/setup.cfg +++ b/setup.cfg @@ -6,3 +6,11 @@ release = 1 build-requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel group = Development/Libraries requires = xmlsec1 xmlsec1-openssl + +[build_sphinx] +source-dir = doc/source +build-dir = doc/build +all_files = 1 + +[upload_docs] +upload-dir = doc/build/html diff --git a/src/ds.c b/src/ds.c index 7a62715b..4eb8b4d9 100644 --- a/src/ds.c +++ b/src/ds.c @@ -96,7 +96,11 @@ static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void return 0; } -static const char PyXmlSec_SignatureContextRegisterId__doc__[] = "Register new id.\n"; +static const char PyXmlSec_SignatureContextRegisterId__doc__[] = \ + "Registers new id.\n\n" + ":param node: the pointer to XML node\n" + ":param id_attr: the attribute\n" + ":param id_ns: the namespace\n"; static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", "id_attr", "id_ns", NULL}; @@ -147,7 +151,9 @@ static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* a return NULL; } -static const char PyXmlSec_SignatureContextSign__doc__[] = "Sign according to the signature template.\n"; +static const char PyXmlSec_SignatureContextSign__doc__[] = \ + "Signs according to the signature template.\n\n" + ":param node: the pointer to node with signature template\n"; static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; @@ -174,7 +180,10 @@ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, P return NULL; } -static const char PyXmlSec_SignatureContextVerify__doc__[] = "Verify according to the signature template.\n"; +static const char PyXmlSec_SignatureContextVerify__doc__[] = \ + "Verifies according to the signature template.\n\n" + ":param node: he pointer with node\n" + ":return: None if success otherwise raises VerificationError\n"; static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; @@ -260,7 +269,10 @@ static int PyXmlSec_ProcessSignBinary(xmlSecDSigCtxPtr ctx, const xmlSecByte* da } static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \ - "Sign binary data *data* with *algorithm* and return the signature.\n"; + "Signs binary data *data* with *algorithm*.\n\n" + ":param bytes: the binary data\n" + ":param transform: the signature algorithm\n" + ":return: the signature\n"; static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", NULL}; @@ -292,7 +304,11 @@ static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* a } static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \ - "Sign binary data *data* with *algorithm* and return the signature.\n"; + "Verifies signature for binary data.\n\n" + ":param bytes: the binary data\n" + ":param transform: the signature algorithm\n" + ":param signature: the signature\n" + ":return: None if success otherwise raises VerificationError\n"; static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", "signature", NULL}; @@ -338,9 +354,10 @@ static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* } static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \ - "Enables use of *t* as reference transform.\n"\ + "Enables use of *t* as reference transform.\n\n"\ "Note: by default, all transforms are enabled. The first call of\n"\ - "`enable_reference_transform` will switch to explicitly enabled transforms.\n"; + "`enable_reference_transform` will switch to explicitly enabled transforms.\n\n" + ":param transform: the transform klass.\n"; static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -370,9 +387,10 @@ static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* sel } static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \ - "Enables use of *t* as signature transform.\n"\ + "Enables use of *t* as signature transform.\n\n"\ "Note: by default, all transforms are enabled. The first call of\n"\ - "`enable_signature_transform` will switch to explicitly enabled transforms.\n"; + "`enable_signature_transform` will switch to explicitly enabled transforms.\n\n" + ":param transform: the transform klass.\n"; static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -401,7 +419,8 @@ static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* sel } static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \ - "Adds selected *KeyData* to the list of enabled key data list.\n"; + "Adds selected *KeyData* to the list of enabled key data list.\n\n" + ":param keydata_list: the list.\n"; static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "keydata_list", NULL}; diff --git a/src/enc.c b/src/enc.c index 3c8fc2ec..d40d9476 100644 --- a/src/enc.c +++ b/src/enc.c @@ -100,8 +100,10 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \ "Encrypts binary *data* according to `EncryptedData` template *template*\n"\ - "returns the resulting `EncryptedData` subtree.\n" \ - "Note: *template* is modified in place.\n"; + "Note: *template* is modified in place.\n\n" + ":param template: the pointer to template node\n" + ":param data: the data\n" + ":return: the resulting subtree\n"; static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "data", NULL}; @@ -150,14 +152,16 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \ "Encrpyts *node* using *template*.\n" \ - "Returns the resulting `EncryptedData` element.\n\n"\ "Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\ "(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\ "It must have one of these two values (or an exception is raised).\n"\ "The operation modifies the tree containing *node* in a way that\n"\ "`lxml` references to or into this tree may see a surprising state.\n"\ "You should no longer rely on them. Especially, you should use\n"\ - "`getroottree()` on the result to obtain the encrypted result tree.\n"; + "`getroottree()` on the result to obtain the encrypted result tree.\n\n" + ":param template: the pointer to template node\n" + ":param node: the pointer to node for encryption\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "node", NULL}; @@ -227,7 +231,10 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* } static const char PyXmlSec_EncryptionContextEncryptUri__doc__[] = \ - "Encrypts binary data obtained from *uri* according to *template*.\n"; + "Encrypts binary data obtained from *uri* according to *template*.\n\n" + ":param template: the pointer to template node\n" + ":param uri: the URI\n" + ":return: the resulting subtree\n"; static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "uri", NULL}; @@ -264,7 +271,10 @@ static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \ "the input tree is modified and a reference to the decrypted XML subtree is returned.\n"\ "If the operation modifies the tree, `lxml` references to or into this tree may see a surprising state.\n"\ "You should no longer rely on them. Especially, you should use `getroottree()` on the result\n"\ - "to obtain the decrypted result tree.\n"; + "to obtain the decrypted result tree.\n\n" + ":param node: the pointer to node\n" + ":return: depends on input parameters\n"; + static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; diff --git a/src/keys.c b/src/keys.c index dc88f29f..c1ee2cbd 100644 --- a/src/keys.c +++ b/src/keys.c @@ -65,7 +65,12 @@ static PyObject* PyXmlSec_Key__copy__(PyObject* self) { return (PyObject*)key2; } -static const char PyXmlSec_KeyFromMemory__doc__[] = "Load PKI key from memory.\n"; +static const char PyXmlSec_KeyFromMemory__doc__[] = \ + "Loads PKI key from memory.\n\n" + ":param data: the binary key data\n" + ":param format: the key file format\n" + ":param password: the key file password\n" + ":return: pointer to newly created key\n"; static PyObject* PyXmlSec_KeyFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", "password", NULL}; @@ -104,9 +109,14 @@ static PyObject* PyXmlSec_KeyFromMemory(PyObject* self, PyObject* args, PyObject return NULL; } -static const char PyXmlSec_KeyFromFile__doc__[] = "Load PKI key from a file.\n"; +static const char PyXmlSec_KeyFromFile__doc__[] = \ + "Loads PKI key from a file.\n\n" + ":param file: the file object or file path\n" + ":param format: the key file format\n" + ":param password: the key file password\n" + ":return: pointer to newly created key\n"; static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = { "data", "format", "password", NULL}; + static char *kwlist[] = { "file", "format", "password", NULL}; PyObject* file = NULL; const char* password = NULL; @@ -162,9 +172,14 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* return NULL; } -static const char PyXmlSec_KeyGenerate__doc__[] = "Generate key of kind *data* with *size* and *type*.\n"; +static const char PyXmlSec_KeyGenerate__doc__[] = \ + "Generates key of kind *data* with *size* and *type*.\n\n" + ":param klass: the requested key klass (rsa, dsa, aes, ...)\n" + ":param size: the new key size (in bits!)\n" + ":param type: the new key type (session, permanent, ...)\n" + ":return: pointer to newly created key\n"; static PyObject* PyXmlSec_KeyGenerate(PyObject* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = { "data", "size", "type", NULL}; + static char *kwlist[] = { "klass", "size", "type", NULL}; PyXmlSec_KeyData* keydata = NULL; short unsigned int keysize = 0; @@ -196,9 +211,13 @@ static PyObject* PyXmlSec_KeyGenerate(PyObject* self, PyObject* args, PyObject* return NULL; } -static const char PyXmlSec_KeyFromBinaryFile__doc__[] = "Loads (symmetric) key of kind *data* from *filename*.\n"; +static const char PyXmlSec_KeyFromBinaryFile__doc__[] = \ + "Loads (symmetric) key of kind *data* from *filename*.\n\n" + ":param klass: the key value data klass\n" + ":param filename: the key binary filename\n" + ":return: pointer to newly created key\n"; static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = { "data", "filename", NULL}; + static char *kwlist[] = { "klass", "filename", NULL}; PyXmlSec_KeyData* keydata = NULL; PyObject* filepath = NULL; @@ -238,7 +257,10 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb return NULL; } -static const char PyXmlSec_KeyCertFromMemory__doc__[] = "Load certificate from memory.\n"; +static const char PyXmlSec_KeyCertFromMemory__doc__[] = \ + "Loads certificate from memory.\n\n" + ":param data: the certificate binary data\n" + ":param format: the certificate file format\n"; static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", NULL}; @@ -271,9 +293,12 @@ static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyOb return NULL; } -static const char PyXmlSec_KeyCertFromFile__doc__[] = "Load certificate from file.\n"; +static const char PyXmlSec_KeyCertFromFile__doc__[] = \ + "Loads certificate from file.\n\n" + ":param file: the file object or file path\n" + ":param format: the certificate file format\n"; static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { - static char *kwlist[] = { "data", "format", NULL}; + static char *kwlist[] = { "file", "format", NULL}; PyObject* file = NULL; unsigned int format = 0; @@ -497,7 +522,9 @@ static void PyXmlSec_KeysManager__del__(PyObject* self) { Py_TYPE(self)->tp_free(self); } -static const char PyXmlSec_KeysManagerAddKey__doc__[] = "Adds a copy of *key*.\n"; +static const char PyXmlSec_KeysManagerAddKey__doc__[] = \ + "Adds a copy of *key* to keys manager\n\n" + ":param key: the pointer to key\n"; static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "key", NULL}; @@ -539,7 +566,11 @@ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyOb return NULL; } -static const char PyXmlSec_KeysManagerLoadCert__doc__[] = "load certificate from *filename*\n*format* - file format\n*type* - key type.\n"; +static const char PyXmlSec_KeysManagerLoadCert__doc__[] = \ + "Loads certificate from *filename*.\n\n" + ":param filename: the certificate file\n" + ":param format: the certificate file format\n" + ":param type: the flag that indicates is the certificate in filename trusted or not\n"; static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "filename", "format", "type", NULL}; @@ -567,7 +598,11 @@ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, Py return NULL; } -static const char PyXmlSec_KeysManagerLoadCertFromMemory__doc__[] = "load certificate from *data*\n*format* - file format\n*type* - key type.\n"; +static const char PyXmlSec_KeysManagerLoadCertFromMemory__doc__[] = \ + "Loads certificate from *data*\n\n" + ":param data: the certificate binary data\n" + ":param format: the certificate file format\n" + ":param type: the flag that indicates is the certificate in filename trusted or not\n"; static PyObject* PyXmlSec_KeysManagerLoadCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", "type", NULL}; diff --git a/src/main.c b/src/main.c index 26842c26..1a0d3729 100644 --- a/src/main.c +++ b/src/main.c @@ -77,10 +77,10 @@ static int PyXmlSec_Init(void) { return 0; } -static char PyXmlSec_PyInit__doc__[] = -"Initialize the library for general operation.\n" \ -"This is called upon library import and does not need to be called\n" \ -"again (unless @ref _shutdown is called explicitly).\n"; +static char PyXmlSec_PyInit__doc__[] = \ + "Initializes the library for general operation.\n\n" + "This is called upon library import and does not need to be called\n" + "again *shutdown* is called explicitly).\n"; static PyObject* PyXmlSec_PyInit(PyObject *self) { if (PyXmlSec_Init() < 0) { return NULL; @@ -88,17 +88,18 @@ static PyObject* PyXmlSec_PyInit(PyObject *self) { Py_RETURN_NONE; } -static char PyXmlSec_PyShutdown__doc__[] = -"Shutdown the library and cleanup any leftover resources.\n" \ -"This is called automatically upon interpreter termination and\n" \ -"should not need to be called explicitly."; +static char PyXmlSec_PyShutdown__doc__[] = \ + "Shutdowns the library and cleanup any leftover resources.\n\n" + "This is called automatically upon interpreter termination and\n" + "should not need to be called explicitly."; static PyObject* PyXmlSec_PyShutdown(PyObject* self) { PyXmlSec_Free(_FREE_ALL); Py_RETURN_NONE; } -static char PyXmlSec_PyEnableDebugOutput__doc__[] = -"Enables or disables calling LibXML2 callback from the default errors callback.\n"; +static char PyXmlSec_PyEnableDebugOutput__doc__[] = \ + "Enables or disables calling LibXML2 callback from the default errors callback.\n\n" + ":param enable_debug_trace: flag, debug trace is enabled or disabled"; static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "enabled", NULL}; PyObject* enabled = Py_True; diff --git a/src/template.c b/src/template.c index cc67b244..f2c4bffe 100644 --- a/src/template.c +++ b/src/template.c @@ -18,8 +18,14 @@ #define PYXMLSEC_TEMPLATES_DOC "Xml Templates processing" static char PyXmlSec_TemplateCreate__doc__[] = \ - "Creates new node with the mandatory , ,\n" - " and children and sub-children.\n"; + "Creates new node with the mandatory , ," + " and children and sub-children.\n\n" + ":param node: the signature node\n" + ":param c14n_method: the signature canonicalization method\n" + ":param sign_method: the signature method\n" + ":param name: the node id (optional)\n" + ":param ns: the namespace prefix for the signature element (e.g. \"dsig\") (optional)\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "c14n_method", "sign_method", "name", "ns", NULL}; @@ -54,8 +60,14 @@ static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObjec } static char PyXmlSec_TemplateAddReference__doc__[] = \ - "Adds node with given URI (uri ), Id (id ) and Type (type ) attributes and\n" - "the required children and to the child of *node*.\n"; + "Adds node with given URI (uri ) Id (id ) and Type (type ) attributes and\n" + "the required children and to the child of *node*.\n\n" + ":param node: the pointer to node\n" + ":param digest_method: the reference digest method\n" + ":param id: the node id (optional)\n" + ":param uri: the reference node uri (optional)\n" + ":param type: the reference node type (optional)\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "digest_method", "id", "uri", "type", NULL}; @@ -89,7 +101,10 @@ static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, P } static char PyXmlSec_TemplateAddTransform__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param transform: the transform method id\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "transform", NULL}; @@ -120,7 +135,10 @@ static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, P } static char PyXmlSec_TemplateEnsureKeyInfo__doc__[] = \ - "Adds (if necessary) node to the node of *node*.\n"; + "Adds (if necessary) node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param id: the node id (optional)\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "id", NULL}; @@ -150,7 +168,10 @@ static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, } static char PyXmlSec_TemplateAddKeyName__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param name: the key name (optional)\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", NULL}; @@ -181,7 +202,9 @@ static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyO } static char PyXmlSec_TemplateAddKeyValue__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -211,7 +234,9 @@ static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, Py } static char PyXmlSec_TemplateAddX509Data__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -241,7 +266,9 @@ static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, Py } static char PyXmlSec_TemplateAddX509DataAddIssuerSerial__doc__[] = \ - "Adds node to the given node of *node*.\n"; + "Adds node to the given node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -271,7 +298,10 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyO } static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param name: the issuer name (optional)\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", NULL}; @@ -302,7 +332,10 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* } static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber__doc__[] = \ - "Adds node to the node of *node*.\n"; + "Adds node to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param serial: the serial number (optional)\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "serial", NULL}; @@ -333,7 +366,9 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(P } static char PyXmlSec_TemplateAddX509DataAddSubjectName__doc__[] = \ - "Adds node to the given node of *node*.\n"; + "Adds node to the given node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -363,7 +398,9 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyOb } static char PyXmlSec_TemplateAddX509DataAddSKI__doc__[] = \ - "Adds node to the given node of *node*.\n"; + "Adds node to the given node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -393,7 +430,9 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *ar } static char PyXmlSec_TemplateAddX509DataAddCertificate__doc__[] = \ - "Adds node to the given node of *node*.\n"; + "Adds node to the given node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -423,7 +462,9 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyOb } static char PyXmlSec_TemplateAddX509DataAddCRL__doc__[] = \ - "Adds node to the given node of *node*.\n"; + "Adds node to the given node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -453,7 +494,13 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *ar } static char PyXmlSec_TemplateAddEncryptedKey__doc__[] = \ - "Adds node with given attributes to the node of *node*.\n"; + "Adds node with given attributes to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param method: the encryption method (optional)\n" + ":param id: the Id attribute (optional)\n" + ":param type: the Type attribute (optional)\n" + ":param recipient: the Recipient attribute (optional)\n" + ":return: the pointer to the newly created node\n"; static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "method", "id", "type", "recipient", NULL}; @@ -487,7 +534,15 @@ static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args } static char PyXmlSec_TemplateCreateEncryptedData__doc__[] = \ - "Creates new <{ns}:EncryptedData /> node for encryption template.\n"; + "Creates new <{ns}:EncryptedData /> node for encryption template.\n\n" + ":param node: the pointer to signature node\n" + ":param method: the encryption method (optional)\n" + ":param id: the Id attribute (optional)\n" + ":param type: the Type attribute (optional)\n" + ":param mime_type: the Recipient attribute (optional)\n" + ":param encoding: the MimeType attribute (optional)\n" + ":param ns: the namespace prefix (optional)\n" + ":return: the pointer newly created node\n"; static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "method", "id", "type", "mime_type", "encoding", "ns", NULL}; @@ -526,7 +581,11 @@ static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject * } static char PyXmlSec_TemplateEncryptedDataEnsureKeyInfo__doc__[] = \ - "Adds <{ns}:KeyInfo/> to the node of *node*.\n"; + "Adds <{ns}:KeyInfo/> to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":param id: the Id attribute (optional)\n" + ":param ns: the namespace prefix (optional)\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "id", "ns", NULL}; @@ -561,7 +620,9 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyO } static char PyXmlSec_TemplateEncryptedDataEnsureCipherValue__doc__[] = \ - "Adds to the node of *node*.\n"; + "Adds to the node of *node*.\n\n" + ":param node: the pointer to node\n" + ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; diff --git a/src/tree.c b/src/tree.c index 788bc546..49d5294e 100644 --- a/src/tree.c +++ b/src/tree.c @@ -16,7 +16,11 @@ #define PYXMLSEC_TREE_DOC "Common XML utility functions" static char PyXmlSec_TreeFindChild__doc__[] = \ - "Searches a direct child of the parent node having given name and namespace href.\n"; + "Searches a direct child of the parent node having given name and namespace href.\n\n" + ":param parent: the pointer to XML node\n" + ":param name: the name\n" + ":param namespace: the namespace href(optional)\n" + ":return: the pointer to the found node or None if node is not found\n"; static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "parent", "name", "namespace", NULL}; @@ -47,7 +51,11 @@ static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject } static char PyXmlSec_TreeFindParent__doc__[] = \ - "Searches the ancestors axis of the node having given name and namespace href.\n"; + "Searches the ancestors axis of the node having given name and namespace href.\n\n" + ":param node: the pointer to XML node\n" + ":param name: the name\n" + ":param namespace: the namespace href(optional)\n" + ":return: the pointer to the found node or None if node is not found\n"; static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", "namespace", NULL}; @@ -78,7 +86,11 @@ static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObjec } static char PyXmlSec_TreeFindNode__doc__[] = \ - "Searches all children of the parent node having given name and namespace href.\n"; + "Searches all children of the parent node having given name and namespace href.\n\n" + ":param node: the pointer to XML node\n" + ":param name: the name\n" + ":param namespace: the namespace href(optional)\n" + ":return: the pointer to the found node or None if node is not found\n"; static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", "namespace", NULL}; @@ -113,7 +125,9 @@ static char PyXmlSec_TreeAddIds__doc__[] = \ "used as XML ids in the subtree rooted at *node*.\n"\ "A call to `addIds` may be necessary to make known which attributes contain XML ids.\n"\ "This is the case, if a transform references an id via `XPointer` or a self document uri and\n" - "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n"; + "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n\n" + ":param node: the pointer to XML node\n" + ":param ids: the list of ID attributes.\n"; static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "ids", NULL}; From a943b27cd9d4ea983400c27fb1426584ee21de83 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sun, 21 May 2017 00:37:41 +0300 Subject: [PATCH 047/378] Added link to documentation --- .travis.yml | 1 + README.rst | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 6f7f4f5c..f1b1a5f6 100644 --- a/.travis.yml +++ b/.travis.yml @@ -28,6 +28,7 @@ before_deploy: deploy: skip_cleanup: true + skip_upload_docs: false provider: pypi user: mehcode on: diff --git a/README.rst b/README.rst index ccf41112..883fe7c1 100644 --- a/README.rst +++ b/README.rst @@ -5,8 +5,8 @@ python-xmlsec :target: https://travis-ci.org/mehcode/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg :target: https://pypi.python.org/pypi/xmlsec -.. image:: https://img.shields.io/pypi/dm/xmlsec.svg - :target: https://pypi.python.org/pypi/xmlsec +.. image:: https://img.shields.io/badge/docs-latest-green.svg + :target: http://pythonhosted.org/xmlsec/ Python bindings for the XML Security Library. From 4a685fcbaa6f94193a4de6924fb45dde01e701b9 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 25 May 2017 22:49:45 +0300 Subject: [PATCH 048/378] Added binding for method xmlSecTmplTransformAddC14NInclNamespaces #59 --- .travis.yml | 3 ++ doc/source/modules/constants.rst | 2 ++ src/constants.c | 2 ++ src/platform.h | 1 + src/template.c | 57 ++++++++++++++++++++++++++++++++ tests/examples/test_templates.py | 35 ++++++++++++++++++++ 6 files changed, 100 insertions(+) create mode 100644 tests/examples/test_templates.py diff --git a/.travis.yml b/.travis.yml index f1b1a5f6..6708afde 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,9 @@ dist: trusty sudo: false language: python +notifications: + email: false + python: - '2.7' - '3.4' diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index c69ef359..460fdd22 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -58,6 +58,8 @@ Namespaces - *XPointerNs* - http://www.w3.org/2001/04/xmldsig-more/xptr - *Soap11Ns* - http://schemas.xmlsoap.org/soap/envelope/ - *Soap12Ns* - http://www.w3.org/2002/06/soap-envelope +- *NsExcC14N* - http://www.w3.org/2001/10/xml-exc-c14n# +- *NsExcC14NWithComments* - http://www.w3.org/2001/10/xml-exc-c14n#WithComments Nodes ***** diff --git a/src/constants.c b/src/constants.c index 4c890729..ad85a210 100644 --- a/src/constants.c +++ b/src/constants.c @@ -292,6 +292,8 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_NS_CONSTANT(XPointerNs, "XPOINTER"); PYXMLSEC_ADD_NS_CONSTANT(Soap11Ns, "SOAP11"); PYXMLSEC_ADD_NS_CONSTANT(Soap12Ns, "SOAP12"); + PYXMLSEC_ADD_NS_CONSTANT(NsExcC14N, "EXC_C14N"); + PYXMLSEC_ADD_NS_CONSTANT(NsExcC14NWithComments, "EXC_C14N_WITH_COMMENT"); PYXMLSEC_CLOSE_NAMESPACE(nsCls); diff --git a/src/platform.h b/src/platform.h index eae902b9..795062f2 100644 --- a/src/platform.h +++ b/src/platform.h @@ -37,6 +37,7 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 +#define PyString_Check PyUnicode_Check #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_FromString PyUnicode_FromString diff --git a/src/template.c b/src/template.c index f2c4bffe..56aa4bf4 100644 --- a/src/template.c +++ b/src/template.c @@ -651,6 +651,57 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, return NULL; } +static char PyXmlSec_TemplateTransformAddC14NInclNamespaces__doc__[] = \ + "Adds 'inclusive' namespaces to the ExcC14N transform node *node*.\n\n" + ":param node: the pointer to node.\n" + ":param prefixList: the list of namespace prefixes, where 'default' indicates the default namespace (optional)."; +static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "node", "prefixes", NULL}; + + PyXmlSec_LxmlElementPtr node = NULL; + PyObject* prefixes = NULL; + // transform_add_c14n_inclusive_namespaces + PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O:transform_add_c14n_inclusive_namespaces", kwlist, + PyXmlSec_LxmlElementConverter, &node, &prefixes)) + { + prefixes = NULL; + goto ON_FAIL; + } + if (PyList_Check(prefixes) || PyTuple_Check(prefixes)) { + PyObject* sep = PyString_FromString(" "); + prefixes = PyObject_CallMethod(sep, "join", "O", prefixes); + Py_DECREF(sep); + } else if (PyString_Check(prefixes)) { + Py_INCREF(prefixes); + } else { + PyErr_SetString(PyExc_TypeError, "expected instance of str or list of str"); + prefixes = NULL; + } + + if (prefixes == NULL) { + goto ON_FAIL; + } + + int res; + const char* c_prefixes = PyString_AsString(prefixes); + Py_BEGIN_ALLOW_THREADS; + res = xmlSecTmplTransformAddC14NInclNamespaces(node->_c_node, XSTR(c_prefixes)); + Py_END_ALLOW_THREADS; + if (res != 0) { + PyXmlSec_SetLastError("cannot add 'inclusive' namespaces to the ExcC14N transform node"); + goto ON_FAIL; + } + + Py_DECREF(prefixes); + PYXMLSEC_DEBUG("transform_add_c14n_inclusive_namespaces - ok"); + Py_RETURN_NONE; + +ON_FAIL: + PYXMLSEC_DEBUG("transform_add_c14n_inclusive_namespaces - fail"); + Py_XDECREF(prefixes); + return NULL; +} static PyMethodDef PyXmlSec_TemplateMethods[] = { { @@ -761,6 +812,12 @@ static PyMethodDef PyXmlSec_TemplateMethods[] = { METH_VARARGS|METH_KEYWORDS, PyXmlSec_TemplateEncryptedDataEnsureCipherValue__doc__ }, + { + "transform_add_c14n_inclusive_namespaces", + (PyCFunction)PyXmlSec_TemplateTransformAddC14NInclNamespaces, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_TemplateTransformAddC14NInclNamespaces__doc__, + }, {NULL, NULL} /* sentinel */ }; diff --git a/tests/examples/test_templates.py b/tests/examples/test_templates.py new file mode 100644 index 00000000..a6fd1b78 --- /dev/null +++ b/tests/examples/test_templates.py @@ -0,0 +1,35 @@ +import xmlsec +from .base import parse_xml +from lxml import etree + + +def _check_transform_add_custom_c14n_inclusive_namespaces(prefixes, expected): + template = parse_xml('sign2-doc.xml') + assert template is not None + + # Create a signature template for RSA-SHA1 enveloped signature. + signature_node = xmlsec.template.create(template, xmlsec.Transform.EXCL_C14N, xmlsec.Transform.RSA_SHA1) + assert signature_node is not None + + # Add the node to the document. + template.append(signature_node) + + # Add the node to the signature template. + ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) + + # Add the enveloped transform descriptor. + transform = xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) + assert transform is not None + + xmlsec.template.transform_add_c14n_inclusive_namespaces(transform, prefixes) + ins = xmlsec.tree.find_child(transform, "InclusiveNamespaces", xmlsec.constants.NsExcC14N) + assert ins is not None + assert expected == ins.get("PrefixList") + + +def test_transform_add_custom_c14n_inclusive_namespaces(): + _check_transform_add_custom_c14n_inclusive_namespaces(["ns1", "ns2"], "ns1 ns2") + + +def test_transform_add_default_c14n_inclusive_namespaces(): + _check_transform_add_custom_c14n_inclusive_namespaces("default", "default") From d5e96e5798515dc3c5e5f41925c6f1b15cb4b888 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 28 Jun 2017 23:08:49 +0300 Subject: [PATCH 049/378] Added more usefull constants --- doc/source/modules/constants.rst | 5 +++++ src/constants.c | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 460fdd22..a9b7c511 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -74,16 +74,21 @@ Nodes - *NodeObject* - Object - *NodeManifest* - Manifest - *NodeEncryptedData* - EncryptedData +- *NodeEncryptedKey* - EncryptedKey - *NodeEncryptionMethod* - EncryptionMethod - *NodeEncryptionProperties* - EncryptionProperties - *NodeEncryptionProperty* - EncryptionProperty - *NodeCipherData* - CipherData - *NodeCipherValue* - CipherValue - *NodeCipherReference* - CipherReference +- *NodeReference - Reference - *NodeReferenceList* - ReferenceList - *NodeDataReference* - DataReference - *NodeKeyReference* - KeyReference - *NodeKeyInfo* - KeyInfo +- *NodeKeyName - KeyName +- *NodeKeyValue - KeyValue +- *NodeX509Data - X509Data Transforms ********** diff --git a/src/constants.c b/src/constants.c index ad85a210..e4f3e440 100644 --- a/src/constants.c +++ b/src/constants.c @@ -348,9 +348,14 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_NODE_CONSTANT(NodeDataReference, "DATA_REFERENCE"); PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyReference, "KEY_REFERENCE"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeReference, "REFERENCE"); PYXMLSEC_ADD_NODE_CONSTANT(NodeReferenceList, "REFERENCE_LIST"); PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyInfo, "KEY_INFO"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyName, "KEY_NAME"); + PYXMLSEC_ADD_NODE_CONSTANT(NodeKeyValue, "KEY_VALUE"); + + PYXMLSEC_ADD_NODE_CONSTANT(NodeX509Data, "X509_DATA"); PYXMLSEC_CLOSE_NAMESPACE(nodeCls); #undef PYXMLSEC_ADD_NODE_CONSTANT From e35c948b803bbeae0578e39f3821365b7b1494b2 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 28 Jun 2017 23:10:02 +0300 Subject: [PATCH 050/378] Fixed wrong parameter description --- src/template.c | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/template.c b/src/template.c index 56aa4bf4..d7bf5826 100644 --- a/src/template.c +++ b/src/template.c @@ -23,28 +23,28 @@ static char PyXmlSec_TemplateCreate__doc__[] = \ ":param node: the signature node\n" ":param c14n_method: the signature canonicalization method\n" ":param sign_method: the signature method\n" - ":param name: the node id (optional)\n" + ":param id: the node id (optional)\n" ":param ns: the namespace prefix for the signature element (e.g. \"dsig\") (optional)\n" ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObject *kwargs) { - static char *kwlist[] = { "node", "c14n_method", "sign_method", "name", "ns", NULL}; + static char *kwlist[] = { "node", "c14n_method", "sign_method", "id", "ns", "name", NULL}; PyXmlSec_LxmlElementPtr node = NULL; PyXmlSec_Transform* c14n = NULL; PyXmlSec_Transform* sign = NULL; - const char* name = NULL; + const char* id = NULL; const char* ns = NULL; PYXMLSEC_DEBUG("template create - start"); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!O!|zz:create", kwlist, - PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &c14n, PyXmlSec_TransformType, &sign, &name, &ns)) + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!O!|zzz:create", kwlist, + PyXmlSec_LxmlElementConverter, &node, PyXmlSec_TransformType, &c14n, PyXmlSec_TransformType, &sign, &id, &ns, &id)) { goto ON_FAIL; } xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; - res = xmlSecTmplSignatureCreateNsPref(node->_doc->_c_doc, c14n->id, sign->id, XSTR(name), XSTR(ns)); + res = xmlSecTmplSignatureCreateNsPref(node->_doc->_c_doc, c14n->id, sign->id, XSTR(id), XSTR(ns)); Py_END_ALLOW_THREADS; if (res == NULL) { PyXmlSec_SetLastError("cannot create template."); @@ -496,7 +496,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *ar static char PyXmlSec_TemplateAddEncryptedKey__doc__[] = \ "Adds node with given attributes to the node of *node*.\n\n" ":param node: the pointer to node\n" - ":param method: the encryption method (optional)\n" + ":param method: the encryption method\n" ":param id: the Id attribute (optional)\n" ":param type: the Type attribute (optional)\n" ":param recipient: the Recipient attribute (optional)\n" @@ -536,7 +536,7 @@ static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args static char PyXmlSec_TemplateCreateEncryptedData__doc__[] = \ "Creates new <{ns}:EncryptedData /> node for encryption template.\n\n" ":param node: the pointer to signature node\n" - ":param method: the encryption method (optional)\n" + ":param method: the encryption method\n" ":param id: the Id attribute (optional)\n" ":param type: the Type attribute (optional)\n" ":param mime_type: the Recipient attribute (optional)\n" From a0b7c9444e827a75f0cb60225649630b342a70ba Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 28 Jun 2017 23:10:26 +0300 Subject: [PATCH 051/378] Fixed warning --- src/tree.c | 1 - 1 file changed, 1 deletion(-) diff --git a/src/tree.c b/src/tree.c index 49d5294e..3d17b329 100644 --- a/src/tree.c +++ b/src/tree.c @@ -232,7 +232,6 @@ int PyXmlSec_TreeModule_Init(PyObject* package) { if (!tree) goto ON_FAIL; - PYXMLSEC_DEBUGF("%", tree); if (PyModule_AddObject(package, "tree", tree) < 0) goto ON_FAIL; return 0; From f02ba8eaa3e13c1f5ac8dcf7abb7c51d8dc8e13b Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sat, 1 Jul 2017 14:13:02 +0300 Subject: [PATCH 052/378] Reworked tests to detect memory leaks --- .travis.yml | 2 +- README.rst | 5 +- tests/base.py | 122 +++++++ tests/conftest.py | 9 - tests/data/deskey.bin | 1 + tests/{examples/enc1-doc.xml => data/doc.xml} | 0 tests/data/dsacert.der | Bin 0 -> 1088 bytes tests/data/dsakey.der | Bin 0 -> 250 bytes tests/data/enc1-in.xml | 7 + .../enc1-res.xml => data/enc1-out.xml} | 0 tests/data/enc2-in.xml | 2 + .../enc2-res.xml => data/enc2-out.xml} | 0 tests/data/enc_template.xml | 9 + tests/{examples => data}/rsacert.pem | 0 tests/{examples => data}/rsakey.pem | 0 tests/{examples => data}/rsapub.pem | 0 .../sign1-tmpl.xml => data/sign1-in.xml} | 0 .../sign1-res.xml => data/sign1-out.xml} | 0 .../sign2-doc.xml => data/sign2-in.xml} | 0 .../sign2-res.xml => data/sign2-out.xml} | 0 .../sign3-doc.xml => data/sign3-in.xml} | 0 .../sign3-res.xml => data/sign3-out.xml} | 0 .../sign4-doc.xml => data/sign4-in.xml} | 0 .../sign4-res.xml => data/sign4-out.xml} | 0 .../sign5-doc.xml => data/sign5-in.xml} | 0 .../sign5-res.xml => data/sign5-out.xml} | 0 tests/data/sign6-in.bin | 1 + tests/data/sign6-out.bin | 3 + tests/data/sign_template.xml | 44 +++ tests/examples/__init__.py | 0 tests/examples/base.py | 20 -- tests/examples/test_decrypt.py | 43 --- tests/examples/test_encrypt.py | 85 ----- tests/examples/test_sign.py | 307 ------------------ tests/examples/test_templates.py | 35 -- tests/examples/test_verify.py | 82 ----- tests/test_ds.py | 193 +++++++++++ tests/test_enc.py | 100 ++++++ tests/test_keys.py | 80 +++++ tests/test_templates.py | 142 ++++++++ tests/test_tree.py | 31 ++ 41 files changed, 740 insertions(+), 583 deletions(-) create mode 100644 tests/base.py delete mode 100644 tests/conftest.py create mode 100644 tests/data/deskey.bin rename tests/{examples/enc1-doc.xml => data/doc.xml} (100%) create mode 100644 tests/data/dsacert.der create mode 100644 tests/data/dsakey.der create mode 100644 tests/data/enc1-in.xml rename tests/{examples/enc1-res.xml => data/enc1-out.xml} (100%) create mode 100644 tests/data/enc2-in.xml rename tests/{examples/enc2-res.xml => data/enc2-out.xml} (100%) create mode 100644 tests/data/enc_template.xml rename tests/{examples => data}/rsacert.pem (100%) rename tests/{examples => data}/rsakey.pem (100%) rename tests/{examples => data}/rsapub.pem (100%) rename tests/{examples/sign1-tmpl.xml => data/sign1-in.xml} (100%) rename tests/{examples/sign1-res.xml => data/sign1-out.xml} (100%) rename tests/{examples/sign2-doc.xml => data/sign2-in.xml} (100%) rename tests/{examples/sign2-res.xml => data/sign2-out.xml} (100%) rename tests/{examples/sign3-doc.xml => data/sign3-in.xml} (100%) rename tests/{examples/sign3-res.xml => data/sign3-out.xml} (100%) rename tests/{examples/sign4-doc.xml => data/sign4-in.xml} (100%) rename tests/{examples/sign4-res.xml => data/sign4-out.xml} (100%) rename tests/{examples/sign5-doc.xml => data/sign5-in.xml} (100%) rename tests/{examples/sign5-res.xml => data/sign5-out.xml} (100%) create mode 100644 tests/data/sign6-in.bin create mode 100644 tests/data/sign6-out.bin create mode 100644 tests/data/sign_template.xml delete mode 100644 tests/examples/__init__.py delete mode 100644 tests/examples/base.py delete mode 100644 tests/examples/test_decrypt.py delete mode 100644 tests/examples/test_encrypt.py delete mode 100644 tests/examples/test_sign.py delete mode 100644 tests/examples/test_templates.py delete mode 100644 tests/examples/test_verify.py create mode 100644 tests/test_ds.py create mode 100644 tests/test_enc.py create mode 100644 tests/test_keys.py create mode 100644 tests/test_templates.py create mode 100644 tests/test_tree.py diff --git a/.travis.yml b/.travis.yml index 6708afde..ba838201 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,7 +23,7 @@ install: - travis_retry pip install -r requirements-test.txt - travis_retry pip install -e "." - pip list -script: py.test tests +script: py.test -v tests before_deploy: - travis_retry pip install Sphinx diff --git a/README.rst b/README.rst index 883fe7c1..5d0ecdb2 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ Python bindings for the XML Security Library. Usage ****** -Check the `examples `_ to see various examples of signing and verifying using the library. +Check the `examples `_ to see various examples of signing and verifying using the library. ************ Requirements @@ -146,6 +146,9 @@ Running the test suite py.test tests +3. Tests configuration +Env variable **PYXMLSEC_TEST_ITERATIONS** specifies number of test iterations to detect memory leaks. + Reporting a issue ----------------- Please attach the output of following information: diff --git a/tests/base.py b/tests/base.py new file mode 100644 index 00000000..abbe6058 --- /dev/null +++ b/tests/base.py @@ -0,0 +1,122 @@ +import gc +import os +import resource +import sys + +from lxml import etree +import xmlsec + +import unittest + +etype = type(etree.Element("test")) + +ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs} + + +def safe_int(s): + try: + return int(s) + except ValueError: + return 0 + + +class TestMemoryLeaks(unittest.TestCase): + maxDiff = None + + iterations = safe_int(os.getenv("PYXMLSEC_TEST_ITERATIONS", "10")) + + data_dir = os.path.join(os.path.dirname(__file__), "data") + + def setUp(self): + gc.disable() + self.addTypeEqualityFunc(etype, "assertXmlEqual") + xmlsec.enable_debug_trace(1) + + def run(self, result=None): + # run first time + super(TestMemoryLeaks, self).run(result=result) + if self.iterations == 0: + return + + m_usage = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + o_count = gc.get_count()[0] + m_hits = 0 + o_hits = 0 + for i in range(self.iterations): + super(TestMemoryLeaks, self).run(result=result) + m_usage_n = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + if m_usage_n > m_usage: + m_usage = m_usage_n + m_hits += 1 + o_count_n = gc.get_count()[0] + if o_count_n > o_count: + o_count = o_count_n + o_hits += 1 + del m_usage_n + del o_count_n + + if m_hits > int(self.iterations * 0.8): + result.buffer = False + try: + raise AssertionError("memory leak detected") + except AssertionError: + result.addError(self, sys.exc_info()) + if o_hits > int(self.iterations * 0.8): + result.buffer = False + try: + raise AssertionError("unreferenced objects detected") + except AssertionError: + result.addError(self, sys.exc_info()) + + def path(self, name): + """returns full path for resource""" + return os.path.join(self.data_dir, name) + + def load(self, name): + """loads resource by name""" + with open(self.path(name), "rb") as stream: + return stream.read() + + def load_xml(self, name, xpath=None): + """returns xml.etree""" + root = etree.parse(self.path(name)).getroot() + if xpath is None: + return root + return root.find(xpath) + + def dump(self, root): + print(etree.tostring(root)) + + def assertXmlEqual(self, first, second, msg=None): + """Checks equality of etree.roots""" + msg = msg or '' + if first.tag != second.tag: + self.fail('Tags do not match: %s and %s. %s' % (first.tag, second.tag, msg)) + for name, value in first.attrib.items(): + if second.attrib.get(name) != value: + self.fail( + 'Attributes do not match: %s=%r, %s=%r. %s' % (name, value, name, second.attrib.get(name), msg) + ) + for name in second.attrib.keys(): + if name not in first.attrib: + self.fail('x2 has an attribute x1 is missing: %s. %s' % (name, msg)) + if not xml_text_compare(first.text, second.text): + self.fail('text: %r != %r. %s' % (first.text, second.text, msg)) + if not xml_text_compare(first.tail, second.tail): + self.fail('tail: %r != %r. %s' % (first.tail, second.tail, msg)) + cl1 = first.getchildren() + cl2 = second.getchildren() + if len(cl1) != len(cl2): + self.fail('children length differs, %i != %i. %s' % (len(cl1), len(cl2), msg)) + i = 0 + for c1, c2 in zip(cl1, cl2): + i += 1 + self.assertXmlEqual(c1, c2) + + +def xml_text_compare(t1, t2): + if not t1 and not t2: + return True + if t1 == '*' or t2 == '*': + return True + return (t1 or '').strip() == (t2 or '').strip() diff --git a/tests/conftest.py b/tests/conftest.py deleted file mode 100644 index 60e9c64d..00000000 --- a/tests/conftest.py +++ /dev/null @@ -1,9 +0,0 @@ -# -*- coding: utf-8 -*- -import sys -from os import path - -# Get the base path. -base = path.join(path.dirname(__file__), '..') - -# Append the source and test packages directories to PATH. -sys.path.append(path.join(base, 'src')) diff --git a/tests/data/deskey.bin b/tests/data/deskey.bin new file mode 100644 index 00000000..019924a7 --- /dev/null +++ b/tests/data/deskey.bin @@ -0,0 +1 @@ +012345670123456701234567 \ No newline at end of file diff --git a/tests/examples/enc1-doc.xml b/tests/data/doc.xml similarity index 100% rename from tests/examples/enc1-doc.xml rename to tests/data/doc.xml diff --git a/tests/data/dsacert.der b/tests/data/dsacert.der new file mode 100644 index 0000000000000000000000000000000000000000..0a5008b411c246964ac0e51da3dc1d317af00cae GIT binary patch literal 1088 zcmXqLVzDu3Vt%%OnTe5!iIZXdqVAo>Yj3SH;AP{~YV&CO&dbQi%F1BSILDCNfRl|m zl!Z;0DKywn*gz1(;SlC>PRz+n%P-2yOfp9r&j7E=jZBI6LJ;f~>C6cd7|cR(`2KtY_>(8R#h$k@=_)WpavN`l|W5GY_`WC;~8Xgp4P4`>>w zgFL`3tPqk~T%r(?ky(_Y;FDUGnxo(n?5Nzu&c(S8=@<*Xr{A_C0D<-)*0I+!s%BcbE{ax<6b*Y^Scw?rSj* z|2*T7?^1lku}Cx|ltp!~+_Wr9V^1bghAGagXRSCXT^--+XB%gfXIvm|c9O|~)%dXG z?B#QBr$775dw9xA$Axz~?0v$$CClXYoqgLmtyOpZf5FDO=~M1*+I!Y%;zZYfQfsTP z+s^4w6O)jcn)2o`voiyegO$36!O6*`QHtL~WqzLPx{?(>^}Oh3=1GU6FQzY@J3aN^ zDwXNiX9d64>!>@u?Wl=k>)$Evcx8oISPhsN z8UGvTuyH1|c`&y9aAM?Tkr$KoFG$S`4)#%SPt8j$0tRvla)=wqg7osSh_Q$)jhL@l zpeyC%?!tU)UHbA}-!)V13>qJU3hpAJK3v7MpvNhH+HR^HQ z!p1F28aEm=uA_ZQ5-{L{q$KvB{QMFHXGaPWOcOj;uSLt%%#I9oOXoh3elNAjWbKlh zq90v#k6xO7dseUa%+(=}%k!ph?mszavBjj?P07bDK#*4@zgH9% zxh)*K)?DHI<_sT-A>s(46;xFOCA}V&YB@7W0u=z1L#vvo$s2oLjZQsYGHx?)7dFWP zKm{|yIh&`Q+h^wU4a1b_L807;KTKCk8Fn7N&FzVng)OiD5rKY}l-;tu%|elpMgAJC zd)Gajh$a>o9F=73;{rfBCrB{KlXY4l_f;JE&WhA(SC!8d^8=E@ThV8wotI_)sw9`! znp5vChM{gh86PMKU$(DZK@!(g2P6axUHke}gxXR literal 0 HcmV?d00001 diff --git a/tests/data/enc1-in.xml b/tests/data/enc1-in.xml new file mode 100644 index 00000000..fd474859 --- /dev/null +++ b/tests/data/enc1-in.xml @@ -0,0 +1,7 @@ + + + +Hello, World! + \ No newline at end of file diff --git a/tests/examples/enc1-res.xml b/tests/data/enc1-out.xml similarity index 100% rename from tests/examples/enc1-res.xml rename to tests/data/enc1-out.xml diff --git a/tests/data/enc2-in.xml b/tests/data/enc2-in.xml new file mode 100644 index 00000000..e108afc7 --- /dev/null +++ b/tests/data/enc2-in.xml @@ -0,0 +1,2 @@ + +test diff --git a/tests/examples/enc2-res.xml b/tests/data/enc2-out.xml similarity index 100% rename from tests/examples/enc2-res.xml rename to tests/data/enc2-out.xml diff --git a/tests/data/enc_template.xml b/tests/data/enc_template.xml new file mode 100644 index 00000000..8db1ee95 --- /dev/null +++ b/tests/data/enc_template.xml @@ -0,0 +1,9 @@ + + + + + + + + + diff --git a/tests/examples/rsacert.pem b/tests/data/rsacert.pem similarity index 100% rename from tests/examples/rsacert.pem rename to tests/data/rsacert.pem diff --git a/tests/examples/rsakey.pem b/tests/data/rsakey.pem similarity index 100% rename from tests/examples/rsakey.pem rename to tests/data/rsakey.pem diff --git a/tests/examples/rsapub.pem b/tests/data/rsapub.pem similarity index 100% rename from tests/examples/rsapub.pem rename to tests/data/rsapub.pem diff --git a/tests/examples/sign1-tmpl.xml b/tests/data/sign1-in.xml similarity index 100% rename from tests/examples/sign1-tmpl.xml rename to tests/data/sign1-in.xml diff --git a/tests/examples/sign1-res.xml b/tests/data/sign1-out.xml similarity index 100% rename from tests/examples/sign1-res.xml rename to tests/data/sign1-out.xml diff --git a/tests/examples/sign2-doc.xml b/tests/data/sign2-in.xml similarity index 100% rename from tests/examples/sign2-doc.xml rename to tests/data/sign2-in.xml diff --git a/tests/examples/sign2-res.xml b/tests/data/sign2-out.xml similarity index 100% rename from tests/examples/sign2-res.xml rename to tests/data/sign2-out.xml diff --git a/tests/examples/sign3-doc.xml b/tests/data/sign3-in.xml similarity index 100% rename from tests/examples/sign3-doc.xml rename to tests/data/sign3-in.xml diff --git a/tests/examples/sign3-res.xml b/tests/data/sign3-out.xml similarity index 100% rename from tests/examples/sign3-res.xml rename to tests/data/sign3-out.xml diff --git a/tests/examples/sign4-doc.xml b/tests/data/sign4-in.xml similarity index 100% rename from tests/examples/sign4-doc.xml rename to tests/data/sign4-in.xml diff --git a/tests/examples/sign4-res.xml b/tests/data/sign4-out.xml similarity index 100% rename from tests/examples/sign4-res.xml rename to tests/data/sign4-out.xml diff --git a/tests/examples/sign5-doc.xml b/tests/data/sign5-in.xml similarity index 100% rename from tests/examples/sign5-doc.xml rename to tests/data/sign5-in.xml diff --git a/tests/examples/sign5-res.xml b/tests/data/sign5-out.xml similarity index 100% rename from tests/examples/sign5-res.xml rename to tests/data/sign5-out.xml diff --git a/tests/data/sign6-in.bin b/tests/data/sign6-in.bin new file mode 100644 index 00000000..b6364f29 --- /dev/null +++ b/tests/data/sign6-in.bin @@ -0,0 +1 @@ +¨f4dP‚Óõ.ÁïĆ«Cì·>Ž££Å¹qc±-¤Bß>ºÑ \ No newline at end of file diff --git a/tests/data/sign6-out.bin b/tests/data/sign6-out.bin new file mode 100644 index 00000000..b6240dd0 --- /dev/null +++ b/tests/data/sign6-out.bin @@ -0,0 +1,3 @@ +h˱‚ú`e‰xåÅirÖÑQš êU_GÌ'¤c£>›27¿^`§pû˜ËÒ± 'â +ì²<Ï@˜=à}O8}fyÂÄéì‡öÁÞý–*o«®É{Ì“yš€o’ë^h| ›<™_—Ëâ7éuÃú_Ìt/sTb  Ó“'´¤zËLDÛㄈ6éJ[çÎÀ±™{Æ:ÿtý«^2÷ž¤ÌTŽ~bÛšºMú½ì)z»‰×²Q¬¯ÜDÍ +6’úo¹Ù–$Î¦ÏøäBb60õÒa±oŒ‹lˆvhµhúú¶6íQÄïúðÉ.^˜PQSž¯Ayä•V ¥dÂ*¶×$À 2¡ \ No newline at end of file diff --git a/tests/data/sign_template.xml b/tests/data/sign_template.xml new file mode 100644 index 00000000..f8523bc5 --- /dev/null +++ b/tests/data/sign_template.xml @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/tests/examples/__init__.py b/tests/examples/__init__.py deleted file mode 100644 index e69de29b..00000000 diff --git a/tests/examples/base.py b/tests/examples/base.py deleted file mode 100644 index b846f5b1..00000000 --- a/tests/examples/base.py +++ /dev/null @@ -1,20 +0,0 @@ -from os import path -from lxml import etree - -BASE_DIR = path.dirname(__file__) - - -def parse_xml(name): - return etree.parse(path.join(BASE_DIR, name)).getroot() - - -def compare(name, result): - # Parse the expected file. - xml = parse_xml(name) - - # Stringify the root, nodes of the two documents. - expected_text = etree.tostring(xml, pretty_print=False) - result_text = etree.tostring(result, pretty_print=False) - - # Compare the results. - assert expected_text == result_text diff --git a/tests/examples/test_decrypt.py b/tests/examples/test_decrypt.py deleted file mode 100644 index b06771b6..00000000 --- a/tests/examples/test_decrypt.py +++ /dev/null @@ -1,43 +0,0 @@ -from __future__ import with_statement -from os import path -import xmlsec -from .base import parse_xml, BASE_DIR, compare - - -def read_from_file(filename): - with open(filename, "rb") as stream: - return stream.read() - - -def test_decrypt1(): - manager = xmlsec.KeysManager() - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.PEM, None) - assert key is not None - manager.add_key(key) - - enc_ctx = xmlsec.EncryptionContext(manager) - - root = parse_xml("enc1-res.xml") - enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.Namespace.ENC) - assert enc_data is not None - decrypted = enc_ctx.decrypt(enc_data) - assert decrypted.tag == "Data" - - compare("enc1-doc.xml", root) - - -def test_decrypt2(): - manager = xmlsec.KeysManager() - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.PEM, None) - assert key is not None - manager.add_key(key) - - enc_ctx = xmlsec.EncryptionContext(manager) - - root = parse_xml("enc2-res.xml") - enc_data = xmlsec.tree.find_child(root, xmlsec.Node.ENCRYPTED_DATA, xmlsec.Namespace.ENC) - assert enc_data is not None - decrypted = enc_ctx.decrypt(enc_data) - assert decrypted.text == "\ntest\n" diff --git a/tests/examples/test_encrypt.py b/tests/examples/test_encrypt.py deleted file mode 100644 index d0fd0f9d..00000000 --- a/tests/examples/test_encrypt.py +++ /dev/null @@ -1,85 +0,0 @@ -from os import path -import xmlsec -from .base import parse_xml, BASE_DIR -from lxml import etree - - -def read_from_file(filename): - with open(filename, "rb") as stream: - return stream.read() - - -def test_encrypt_xml(): - # Load the public cert - manager = xmlsec.KeysManager() - filename = path.join(BASE_DIR, 'rsacert.pem') - key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.CERT_PEM, None) - assert key is not None - manager.add_key(key) - template = parse_xml('enc1-doc.xml') - assert template is not None - # Prepare for encryption - enc_data = xmlsec.template.encrypted_data_create( - template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.ELEMENT, ns="xenc") - - xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") - enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) - xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) - - data = template.find('./Data') - - assert data is not None - # Encrypt! - enc_ctx = xmlsec.EncryptionContext(manager) - enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 128, xmlsec.KeyDataType.SESSION) - enc_datsa = enc_ctx.encrypt_xml(enc_data, data) - assert enc_data is not None - enc_method = xmlsec.tree.find_child(enc_data, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC) - assert enc_method is not None - assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#aes128-cbc" - key_info = xmlsec.tree.find_child(enc_data, xmlsec.Node.KEY_INFO, xmlsec.Namespace.DS) - assert key_info is not None - enc_method = xmlsec.tree.find_node(key_info, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC) - assert enc_method is not None - assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" - cipher_value = xmlsec.tree.find_node(key_info, xmlsec.Node.CIPHER_VALUE, xmlsec.Namespace.ENC) - assert cipher_value is not None - - -def test_encrypt_binary(): - # Load the public cert - manager = xmlsec.KeysManager() - filename = path.join(BASE_DIR, 'rsacert.pem') - key = xmlsec.Key.from_memory(read_from_file(filename), xmlsec.KeyFormat.CERT_PEM, None) - assert key is not None - manager.add_key(key) - template = etree.Element("root") - assert template is not None - # Prepare for encryption - enc_data = xmlsec.template.encrypted_data_create( - template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns="xenc", - mime_type="binary/octet-stream") - - xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") - enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) - xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) - - # Encrypt! - enc_ctx = xmlsec.EncryptionContext(manager) - enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 128, xmlsec.KeyDataType.SESSION) - enc_data = enc_ctx.encrypt_binary(enc_data, b'test') - assert enc_data is not None - assert enc_data.tag == "{%s}%s" % (xmlsec.Namespace.ENC, xmlsec.Node.ENCRYPTED_DATA) - print(xmlsec.Node.ENCRYPTION_METHOD) - enc_method = xmlsec.tree.find_child(enc_data, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC) - assert enc_method is not None - assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#aes128-cbc" - key_info = xmlsec.tree.find_child(enc_data, xmlsec.Node.KEY_INFO, xmlsec.Namespace.DS) - assert key_info is not None - enc_method = xmlsec.tree.find_node(key_info, xmlsec.Node.ENCRYPTION_METHOD, xmlsec.Namespace.ENC) - assert enc_method is not None - assert enc_method.get("Algorithm") == "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p" - cipher_value = xmlsec.tree.find_node(key_info, xmlsec.Node.CIPHER_VALUE, xmlsec.Namespace.ENC) - assert cipher_value is not None diff --git a/tests/examples/test_sign.py b/tests/examples/test_sign.py deleted file mode 100644 index d873ba8c..00000000 --- a/tests/examples/test_sign.py +++ /dev/null @@ -1,307 +0,0 @@ -from os import path -import xmlsec -from .base import parse_xml, compare, BASE_DIR - - -def test_sign_template_pem(): - """ - Should sign a pre-constructed template file - using a key from a PEM file. - """ - - # Load the pre-constructed XML template. - template = parse_xml('sign1-tmpl.xml') - - # Find the node. - signature_node = xmlsec.tree.find_node(template, xmlsec.Node.SIGNATURE) - - assert signature_node is not None - assert signature_node.tag.endswith(xmlsec.Node.SIGNATURE) - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load private key (assuming that there is no password). - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - del key - - # Sign the template. - ctx.sign(signature_node) - - # Assert the contents of the XML document against the expected result. - compare('sign1-res.xml', template) - - -def test_sign_generated_template_pem(): - """ - Should sign a dynamicaly constructed template file - using a key from a PEM file. - """ - - # Load document file. - template = parse_xml('sign2-doc.xml') - - # Create a signature template for RSA-SHA1 enveloped signature. - signature_node = xmlsec.template.create( - template, - xmlsec.Transform.EXCL_C14N, - xmlsec.Transform.RSA_SHA1) - - assert signature_node is not None - - # Add the node to the document. - template.append(signature_node) - - # Add the node to the signature template. - ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) - - # Add the enveloped transform descriptor. - xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) - - # Add the and nodes. - key_info = xmlsec.template.ensure_key_info(signature_node) - xmlsec.template.add_key_name(key_info) - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load private key (assuming that there is no password). - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - # Sign the template. - ctx.sign(signature_node) - - # Assert the contents of the XML document against the expected result. - compare('sign2-res.xml', template) - - -def test_sign_generated_template_pem_with_x509(): - """ - Should sign a file using a dynamicaly created template, key from PEM - file and an X509 certificate. - """ - - # Load document file. - template = parse_xml('sign3-doc.xml') - - # Create a signature template for RSA-SHA1 enveloped signature. - signature_node = xmlsec.template.create( - template, - xmlsec.Transform.EXCL_C14N, - xmlsec.Transform.RSA_SHA1) - - assert signature_node is not None - - # Add the node to the document. - template.append(signature_node) - - # Add the node to the signature template. - ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) - - # Add the enveloped transform descriptor. - xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) - - # Add the and nodes. - key_info = xmlsec.template.ensure_key_info(signature_node) - xmlsec.template.add_x509_data(key_info) - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load private key (assuming that there is no password). - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Load the certificate and add it to the key. - filename = path.join(BASE_DIR, 'rsacert.pem') - key.load_cert_from_file(filename, xmlsec.KeyFormat.PEM) - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - # Sign the template. - ctx.sign(signature_node) - - # Assert the contents of the XML document against the expected result. - compare('sign3-res.xml', template) - - -def test_sign_generated_template_pem_with_x509_with_custom_ns(): - """ - Should sign a file using a dynamicaly created template, key from PEM - file and an X509 certificate with custom ns. - """ - - # Load document file. - template = parse_xml('sign4-doc.xml') - xmlsec.tree.add_ids(template, ["ID"]) - elem_id = template.get('ID', None) - if elem_id: - elem_id = '#' + elem_id - # Create a signature template for RSA-SHA1 enveloped signature. - signature_node = xmlsec.template.create( - template, - xmlsec.Transform.EXCL_C14N, - xmlsec.Transform.RSA_SHA1, ns='ds') - - assert signature_node is not None - - # Add the node to the document. - template.append(signature_node) - - # Add the node to the signature template. - ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1, uri=elem_id) - - # Add the enveloped transform descriptor. - xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) - # Add the excl_c14n transform descriptor. - xmlsec.template.add_transform(ref, xmlsec.Transform.EXCL_C14N) - - # Add the and nodes. - key_info = xmlsec.template.ensure_key_info(signature_node) - xmlsec.template.add_x509_data(key_info) - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load private key (assuming that there is no password). - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Load the certificate and add it to the key. - filename = path.join(BASE_DIR, 'rsacert.pem') - key.load_cert_from_file(filename, xmlsec.KeyFormat.PEM) - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - # Sign the template. - ctx.sign(signature_node) - - # Assert the contents of the XML document against the expected result. - compare('sign4-res.xml', template) - - -def test_sign_generated_template_pem_with_x509_with_cert_info(): - """ - Should sign a file using a dynamicaly created template, key from PEM - file and an X509 certificate. - """ - - # Load document file. - template = parse_xml('sign5-doc.xml') - - # Create a signature template for RSA-SHA1 enveloped signature. - signature_node = xmlsec.template.create( - template, - xmlsec.Transform.EXCL_C14N, - xmlsec.Transform.RSA_SHA1) - - assert signature_node is not None - - # Add the node to the document. - template.append(signature_node) - - # Add the node to the signature template. - ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) - - # Add the enveloped transform descriptor. - xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) - - # Add the and nodes. - key_info = xmlsec.template.ensure_key_info(signature_node) - x509_data = xmlsec.template.add_x509_data(key_info) - xmlsec.template.x509_data_add_subject_name(x509_data) - xmlsec.template.x509_data_add_certificate(x509_data) - xmlsec.template.x509_data_add_ski(x509_data) - x509_issuer_serial = xmlsec.template.x509_data_add_issuer_serial(x509_data) - xmlsec.template.x509_issuer_serial_add_issuer_name(x509_issuer_serial, 'Test Issuer') - xmlsec.template.x509_issuer_serial_add_serial_number(x509_issuer_serial, '1') - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load private key (assuming that there is no password). - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Load the certificate and add it to the key. - filename = path.join(BASE_DIR, 'rsacert.pem') - key.load_cert_from_file(filename, xmlsec.KeyFormat.PEM) - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - # Sign the template. - ctx.sign(signature_node) - - # Assert the contents of the XML document against the expected result. - compare('sign5-res.xml', template) - - -def test_sign_binary(): - ctx = xmlsec.SignatureContext() - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - assert key is not None - - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' - expected_sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" - sign = ctx.sign_binary(data, xmlsec.Transform.RSA_SHA1) - assert sign == expected_sign diff --git a/tests/examples/test_templates.py b/tests/examples/test_templates.py deleted file mode 100644 index a6fd1b78..00000000 --- a/tests/examples/test_templates.py +++ /dev/null @@ -1,35 +0,0 @@ -import xmlsec -from .base import parse_xml -from lxml import etree - - -def _check_transform_add_custom_c14n_inclusive_namespaces(prefixes, expected): - template = parse_xml('sign2-doc.xml') - assert template is not None - - # Create a signature template for RSA-SHA1 enveloped signature. - signature_node = xmlsec.template.create(template, xmlsec.Transform.EXCL_C14N, xmlsec.Transform.RSA_SHA1) - assert signature_node is not None - - # Add the node to the document. - template.append(signature_node) - - # Add the node to the signature template. - ref = xmlsec.template.add_reference(signature_node, xmlsec.Transform.SHA1) - - # Add the enveloped transform descriptor. - transform = xmlsec.template.add_transform(ref, xmlsec.Transform.ENVELOPED) - assert transform is not None - - xmlsec.template.transform_add_c14n_inclusive_namespaces(transform, prefixes) - ins = xmlsec.tree.find_child(transform, "InclusiveNamespaces", xmlsec.constants.NsExcC14N) - assert ins is not None - assert expected == ins.get("PrefixList") - - -def test_transform_add_custom_c14n_inclusive_namespaces(): - _check_transform_add_custom_c14n_inclusive_namespaces(["ns1", "ns2"], "ns1 ns2") - - -def test_transform_add_default_c14n_inclusive_namespaces(): - _check_transform_add_custom_c14n_inclusive_namespaces("default", "default") diff --git a/tests/examples/test_verify.py b/tests/examples/test_verify.py deleted file mode 100644 index 7d8c2054..00000000 --- a/tests/examples/test_verify.py +++ /dev/null @@ -1,82 +0,0 @@ -from os import path -from pytest import mark -import xmlsec -from .base import parse_xml, BASE_DIR - - -@mark.parametrize('index', range(1, 5)) -def test_verify_with_pem_file(index): - """Should verify a signed file using a key from a PEM file. - """ - - # Load the XML document. - template = parse_xml('sign%d-res.xml' % index) - xmlsec.tree.add_ids(template, ["ID"]) - # Find the node. - signature_node = xmlsec.tree.find_node(template, xmlsec.Node.SIGNATURE) - - assert signature_node is not None - assert signature_node.tag.endswith(xmlsec.Node.SIGNATURE) - - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - - # Load the public key. - filename = path.join(BASE_DIR, 'rsapub.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - - assert key is not None - - # Set key name to the file name (note: this is just a test). - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - # Verify the signature. - ctx.verify(signature_node) - - -def test_validate_binary_sign(): - ctx = xmlsec.SignatureContext() - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - assert key is not None - - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' - sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" - ctx.verify_binary(data, xmlsec.Transform.RSA_SHA1, sign) - - -def test_validate_binary_sign_fail(): - ctx = xmlsec.SignatureContext() - filename = path.join(BASE_DIR, 'rsakey.pem') - key = xmlsec.Key.from_file(filename, xmlsec.KeyFormat.PEM) - assert key is not None - - key.name = path.basename(filename) - - # Set the key on the context. - ctx.key = key - - assert ctx.key is not None - assert ctx.key.name == path.basename(filename) - - data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' - sign = b"invalid" - try: - ctx.verify_binary(data, xmlsec.Transform.RSA_SHA1, sign) - assert False - except xmlsec.Error: - pass diff --git a/tests/test_ds.py b/tests/test_ds.py new file mode 100644 index 00000000..26d49075 --- /dev/null +++ b/tests/test_ds.py @@ -0,0 +1,193 @@ +from tests import base + +import xmlsec + + +consts = xmlsec.constants + + +class TestSignContext(base.TestMemoryLeaks): + def test_init(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + del ctx + + def test_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + self.assertIsNone(ctx.key) + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + + def test_register_id(self): + ctx = xmlsec.SignatureContext() + root = self.load_xml("sign_template.xml") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id") + ctx.register_id(sign, "Id") + + def test_sign_case1(self): + """Should sign a pre-constructed template file using a key from a PEM file.""" + root = self.load_xml("sign1-in.xml") + sign = xmlsec.tree.find_node(root, consts.NodeSignature) + self.assertIsNotNone(sign) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign1-out.xml"), root) + + def test_sign_case2(self): + """Should sign a dynamicaly constructed template file using a key from a PEM file.""" + root = self.load_xml("sign2-in.xml") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) + self.assertIsNotNone(sign) + root.append(sign) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1) + xmlsec.template.add_transform(ref, consts.TransformEnveloped) + ki = xmlsec.template.ensure_key_info(sign) + xmlsec.template.add_key_name(ki) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign2-out.xml"), root) + + def test_sign_case3(self): + """Should sign a file using a dynamicaly created template, key from PEM and an X509 cert.""" + root = self.load_xml("sign3-in.xml") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) + self.assertIsNotNone(sign) + root.append(sign) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1) + xmlsec.template.add_transform(ref, consts.TransformEnveloped) + ki = xmlsec.template.ensure_key_info(sign) + xmlsec.template.add_x509_data(ki) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign3-out.xml"), root) + + def test_sign_case4(self): + """Should sign a file using a dynamically created template, key from PEM and an X509 cert with custom ns.""" + + root = self.load_xml("sign4-in.xml") + xmlsec.tree.add_ids(root, ["ID"]) + elem_id = root.get('ID', None) + if elem_id: + elem_id = '#' + elem_id + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, ns="ds") + self.assertIsNotNone(sign) + root.append(sign) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1, uri=elem_id) + xmlsec.template.add_transform(ref, consts.TransformEnveloped) + xmlsec.template.add_transform(ref, consts.TransformExclC14N) + ki = xmlsec.template.ensure_key_info(sign) + xmlsec.template.add_x509_data(ki) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign4-out.xml"), root) + + def test_sign_case5(self): + """Should sign a file using a dynamicaly created template, key from PEM file and an X509 certificate.""" + root = self.load_xml("sign5-in.xml") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) + self.assertIsNotNone(sign) + root.append(sign) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1) + xmlsec.template.add_transform(ref, consts.TransformEnveloped) + + ki = xmlsec.template.ensure_key_info(sign) + x509 = xmlsec.template.add_x509_data(ki) + xmlsec.template.x509_data_add_subject_name(x509) + xmlsec.template.x509_data_add_certificate(x509) + xmlsec.template.x509_data_add_ski(x509) + x509_issuer_serial = xmlsec.template.x509_data_add_issuer_serial(x509) + xmlsec.template.x509_issuer_serial_add_issuer_name(x509_issuer_serial, 'Test Issuer') + xmlsec.template.x509_issuer_serial_add_serial_number(x509_issuer_serial, '1') + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign5-out.xml"), root) + + def test_sign_binary(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + sign = ctx.sign_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1) + self.assertEqual(self.load("sign6-out.bin"), sign) + + def test_verify_case_1(self): + self.check_verify(1) + + def test_verify_case_2(self): + self.check_verify(2) + + def test_verify_case_3(self): + self.check_verify(3) + + def test_verify_case_4(self): + self.check_verify(4) + + def test_verify_case_5(self): + self.check_verify(5) + + def check_verify(self, i): + root = self.load_xml("sign%d-out.xml" % i) + xmlsec.tree.add_ids(root, ["ID"]) + sign = xmlsec.tree.find_node(root, consts.NodeSignature) + self.assertIsNotNone(sign) + self.assertEqual(consts.NodeSignature, sign.tag.partition("}")[2]) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsapub.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsapub.pem' + self.assertEqual("rsapub.pem", ctx.key.name) + ctx.verify(sign) + + def test_validate_binary_sign(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, self.load("sign6-out.bin")) + + def test_validate_binary_sign_fail(self): + ctx = xmlsec.SignatureContext() + + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + with self.assertRaises(xmlsec.Error): + ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, b"invalid") diff --git a/tests/test_enc.py b/tests/test_enc.py new file mode 100644 index 00000000..c852642a --- /dev/null +++ b/tests/test_enc.py @@ -0,0 +1,100 @@ +from tests import base + +import xmlsec + + +consts = xmlsec.constants + + +class TestEncryptionContext(base.TestMemoryLeaks): + def test_init(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + del ctx + + def test_key(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + self.assertIsNone(ctx.key) + ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + self.assertIsNotNone(ctx.key) + + def test_encrypt_xml(self): + root = self.load_xml('enc1-in.xml') + enc_data = xmlsec.template.encrypted_data_create( + root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns="xenc" + ) + xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) + xmlsec.template.encrypted_data_ensure_cipher_value(ek) + data = root.find('./Data') + self.assertIsNotNone(data) + + manager = xmlsec.KeysManager() + manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + + ctx = xmlsec.EncryptionContext(manager) + ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) + + encrypted = ctx.encrypt_xml(enc_data, data) + self.assertIsNotNone(encrypted) + + enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) + self.assertIsNotNone(ki) + enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method2) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) + self.assertIsNotNone(cipher_value) + + def test_encrypt_binary(self): + root = self.load_xml('enc2-in.xml') + enc_data = xmlsec.template.encrypted_data_create( + root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream" + ) + xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) + xmlsec.template.encrypted_data_ensure_cipher_value(ek) + + manager = xmlsec.KeysManager() + manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + + ctx = xmlsec.EncryptionContext(manager) + ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) + + encrypted = ctx.encrypt_binary(enc_data, b'test') + self.assertIsNotNone(encrypted) + self.assertEqual("{%s}%s" % (consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + + enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + + ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) + self.assertIsNotNone(ki) + enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method2) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) + self.assertIsNotNone(cipher_value) + + def test_decrypt1(self): + self.check_decrypt(1) + + def test_decrypt2(self): + self.check_decrypt(2) + + def check_decrypt(self, i, ): + root = self.load_xml('enc%d-out.xml' % i) + enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs) + self.assertIsNotNone(enc_data) + + manager = xmlsec.KeysManager() + manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + ctx = xmlsec.EncryptionContext(manager) + decrypted = ctx.decrypt(enc_data) + self.assertIsNotNone(decrypted) + self.assertEqual(self.load_xml("enc%d-in.xml" % i), root) diff --git a/tests/test_keys.py b/tests/test_keys.py new file mode 100644 index 00000000..081b85d5 --- /dev/null +++ b/tests/test_keys.py @@ -0,0 +1,80 @@ +from tests import base + +import copy + +import xmlsec + + +consts = xmlsec.constants + + +class TestKeys(base.TestMemoryLeaks): + def test_key_from_memory(self): + key = xmlsec.Key.from_memory(self.load("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + + def test_key_from_file(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + + def test_key_from_fileobj(self): + with open(self.path("rsakey.pem"), "rb") as fobj: + key = xmlsec.Key.from_file(fobj, format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + + def test_generate(self): + key = xmlsec.Key.generate(klass=consts.KeyDataAes, size=256, type=consts.KeyDataTypeSession) + self.assertIsNotNone(key) + + def test_from_binary_file(self): + key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path("deskey.bin")) + self.assertIsNotNone(key) + + def test_load_cert_from_file(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + key.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem) + + def test_load_cert_from_fileobj(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with open(self.path("rsacert.pem"), "rb") as fobj: + key.load_cert_from_file(fobj, format=consts.KeyDataFormatPem) + + def test_load_cert_from_memory(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + key.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem) + + def test_name(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key.name = "rsakey" + self.assertEqual("rsakey", key.name) + + def test_copy(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key2 = copy.copy(key) + del key + key2.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem) + + +class TestKeysManager(base.TestMemoryLeaks): + def test_add_key(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + mngr = xmlsec.KeysManager() + mngr.add_key(key) + + def test_load_cert(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + mngr.load_cert(self.path("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + + def test_load_cert_from_memory(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + mngr.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + + def test_load_invalid_key(self): + mngr = xmlsec.KeysManager() + with self.assertRaises(ValueError): + mngr.add_key(xmlsec.Key()) diff --git a/tests/test_templates.py b/tests/test_templates.py new file mode 100644 index 00000000..dcd8d940 --- /dev/null +++ b/tests/test_templates.py @@ -0,0 +1,142 @@ +from tests import base + +import xmlsec + + +consts = xmlsec.constants + + +class TestTemplates(base.TestMemoryLeaks): + def test_create(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create( + root, + c14n_method=consts.TransformExclC14N, + sign_method=consts.TransformRsaSha1, + id="Id", + ns="test" + ) + self.assertEqual("Id", sign.get("Id")) + self.assertEqual("test", sign.prefix) + + def test_encrypt_data_create(self): + root = self.load_xml("doc.xml") + enc = xmlsec.template.encrypted_data_create( + root, method=consts.TransformDes3Cbc, id="Id", type="Type", mime_type="MimeType", encoding="Encoding", + ns="test" + ) + for a in ("Id", "Type", "MimeType", "Encoding"): + self.assertEqual(a, enc.get(a)) + self.assertEqual("test", enc.prefix) + + def test_ensure_key_info(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign, id="Id") + self.assertEqual("Id", ki.get("Id")) + + def test_add_encrypted_key(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) + self.assertEqual( + ek, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeEncryptedKey, consts.EncNs) + ) + ek2 = xmlsec.template.add_encrypted_key( + ki, consts.TransformRsaOaep, id="Id", type="Type", recipient="Recipient" + ) + for a in ("Id", "Type", "Recipient"): + self.assertEqual(a, ek2.get(a)) + + def test_add_key_name(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + kn = xmlsec.template.add_key_name(ki) + self.assertEqual( + kn, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyName, consts.DSigNs) + ) + kn2 = xmlsec.template.add_key_name(ki, name="name") + self.assertEqual("name", kn2.text) + + def test_add_reference(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1, id="Id", uri="URI", type="Type") + for a in ("Id", "URI", "Type"): + self.assertEqual(a, ref.get(a)) + + def test_add_key_value(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + kv = xmlsec.template.add_key_value(ki) + self.assertEqual( + kv, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyValue, consts.DSigNs) + ) + + def test_add_x509_data(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + x509 = xmlsec.template.add_x509_data(ki) + xmlsec.template.x509_data_add_certificate(x509) + xmlsec.template.x509_data_add_crl(x509) + issuer = xmlsec.template.x509_data_add_issuer_serial(x509) + xmlsec.template.x509_data_add_ski(x509) + xmlsec.template.x509_data_add_subject_name(x509) + xmlsec.template.x509_issuer_serial_add_issuer_name(issuer) + xmlsec.template.x509_issuer_serial_add_serial_number(issuer) + self.assertEqual( + x509, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeX509Data, consts.DSigNs) + ) + + def test_x509_issuer_serial_add_issuer(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + x509 = xmlsec.template.add_x509_data(ki) + issuer = xmlsec.template.x509_data_add_issuer_serial(x509) + name = xmlsec.template.x509_issuer_serial_add_issuer_name(issuer, name="Name") + serial = xmlsec.template.x509_issuer_serial_add_serial_number(issuer, serial="Serial") + self.assertEqual("Name", name.text) + self.assertEqual("Serial", serial.text) + + def test_encrypted_data_ensure_cipher_value(self): + root = self.load_xml("doc.xml") + enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) + cv = xmlsec.template.encrypted_data_ensure_cipher_value(enc) + self.assertEqual( + cv, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeCipherValue, consts.EncNs) + ) + + def test_encrypted_data_ensure_key_info(self): + root = self.load_xml("doc.xml") + enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) + ki = xmlsec.template.encrypted_data_ensure_key_info(enc) + self.assertEqual( + ki, + xmlsec.tree.find_node(self.load_xml("enc_template.xml"), consts.NodeKeyInfo, consts.DSigNs) + ) + ki2 = xmlsec.template.encrypted_data_ensure_key_info(enc, id="Id", ns="test") + self.assertEqual("Id", ki2.get("Id")) + self.assertEqual("test", ki2.prefix) + + def test_transform_add_c14n_inclusive_namespaces(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ref = xmlsec.template.add_reference(sign, consts.TransformSha1) + trans1 = xmlsec.template.add_transform(ref, consts.TransformEnveloped) + xmlsec.template.transform_add_c14n_inclusive_namespaces(trans1, "default") + trans2 = xmlsec.template.add_transform(ref, consts.TransformXslt) + xmlsec.template.transform_add_c14n_inclusive_namespaces(trans2, ["ns1", "ns2"]) + self.assertEqual( + ref, + xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeReference, consts.DSigNs) + ) diff --git a/tests/test_tree.py b/tests/test_tree.py new file mode 100644 index 00000000..f07c654c --- /dev/null +++ b/tests/test_tree.py @@ -0,0 +1,31 @@ +from tests import base + +import xmlsec + + +consts = xmlsec.constants + + +class TestTree(base.TestMemoryLeaks): + def test_find_child(self): + root = self.load_xml("sign_template.xml") + si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs) + self.assertEqual(consts.NodeSignedInfo, si.tag.partition('}')[2]) + self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeReference)) + self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.EncNs)) + + def test_find_parent(self): + root = self.load_xml("sign_template.xml") + si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs) + self.assertIs(root, xmlsec.tree.find_parent(si, consts.NodeSignature)) + self.assertIsNone(xmlsec.tree.find_parent(root, consts.NodeSignedInfo)) + + def test_find_node(self): + root = self.load_xml("sign_template.xml") + ref = xmlsec.tree.find_node(root, consts.NodeReference) + self.assertEqual(consts.NodeReference, ref.tag.partition('}')[2]) + self.assertIsNone(xmlsec.tree.find_node(root, consts.NodeReference, consts.EncNs)) + + def test_add_ids(self): + root = self.load_xml("sign_template.xml") + xmlsec.tree.add_ids(root, ["id1", "id2", "id3"]) From 20321f2bdfa03e4a26e13e53e9c75c9af8bce96a Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 28 Jun 2017 23:11:10 +0300 Subject: [PATCH 053/378] Fixed memory leaks #63 --- src/ds.c | 18 +++++++++++++----- src/enc.c | 36 ++++++++++++++++++++++-------------- src/exception.c | 1 + src/keys.c | 18 ++++++++++++++---- src/lxml.c | 5 +++++ src/lxml.h | 3 ++- 6 files changed, 57 insertions(+), 24 deletions(-) diff --git a/src/ds.c b/src/ds.c index 4eb8b4d9..70499543 100644 --- a/src/ds.c +++ b/src/ds.c @@ -39,17 +39,20 @@ static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyO PYXMLSEC_DEBUGF("%p: init sign context", self); PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { - return -1; + goto ON_FAIL; } - PYXMLSEC_DEBUGF("%p", manager); ctx->handle = xmlSecDSigCtxCreate(manager != NULL ? manager->handle : NULL); if (ctx->handle == NULL) { PyXmlSec_SetLastError("failed to create the digital signature context"); - return -1; + goto ON_FAIL; } - Py_XINCREF(manager); ctx->manager = manager; + PYXMLSEC_DEBUGF("%p: init sign context - ok, manager - %p", self, manager); return 0; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: init sign context - failed", self); + Py_XDECREF(manager); + return -1; } static void PyXmlSec_SignatureContext__del__(PyObject* self) { @@ -65,8 +68,13 @@ static void PyXmlSec_SignatureContext__del__(PyObject* self) { static const char PyXmlSec_SignatureContextKey__doc__[] = "Signature key.\n"; static PyObject* PyXmlSec_SignatureContextKeyGet(PyObject* self, void* closure) { + PyXmlSec_SignatureContext* ctx = ((PyXmlSec_SignatureContext*)self); + if (ctx->handle->signKey == NULL) { + Py_RETURN_NONE; + } + PyXmlSec_Key* key = PyXmlSec_NewKey(); - key->handle = ((PyXmlSec_SignatureContext*)self)->handle->signKey; + key->handle = ctx->handle->signKey; key->is_own = 0; return (PyObject*)key; } diff --git a/src/enc.c b/src/enc.c index d40d9476..176511d9 100644 --- a/src/enc.c +++ b/src/enc.c @@ -24,7 +24,7 @@ typedef struct { static PyObject* PyXmlSec_EncryptionContext__new__(PyTypeObject *type, PyObject *args, PyObject *kwargs) { PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)PyType_GenericNew(type, args, kwargs); - PYXMLSEC_DEBUGF("%p: new sign context", ctx); + PYXMLSEC_DEBUGF("%p: new enc context", ctx); if (ctx != NULL) { ctx->handle = NULL; ctx->manager = NULL; @@ -37,24 +37,26 @@ static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, Py PyXmlSec_KeysManager* manager = NULL; PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; - PYXMLSEC_DEBUGF("%p: init sign context", self); + PYXMLSEC_DEBUGF("%p: init enc context", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { - return -1; + goto ON_FAIL; } - - PYXMLSEC_DEBUGF("%p", manager); ctx->handle = xmlSecEncCtxCreate(manager != NULL ? manager->handle : NULL); if (ctx->handle == NULL) { - PyXmlSec_SetLastError("failed to create the digital signature context"); - return -1; + PyXmlSec_SetLastError("failed to create the encryption context"); + goto ON_FAIL; } - Py_XINCREF(manager); ctx->manager = manager; + PYXMLSEC_DEBUGF("%p: init enc context - ok, manager - %p", self, manager); return 0; +ON_FAIL: + PYXMLSEC_DEBUGF("%p: init enc context - failed", self); + Py_XDECREF(manager); + return -1; } static void PyXmlSec_EncryptionContext__del__(PyObject* self) { - PYXMLSEC_DEBUGF("%p: delete sign context", self); + PYXMLSEC_DEBUGF("%p: delete enc context", self); PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; if (ctx->handle != NULL) { xmlSecEncCtxDestroy(ctx->handle); @@ -66,8 +68,13 @@ static void PyXmlSec_EncryptionContext__del__(PyObject* self) { static const char PyXmlSec_EncryptionContextKey__doc__[] = "Encryption key.\n"; static PyObject* PyXmlSec_EncryptionContextKeyGet(PyObject* self, void* closure) { + PyXmlSec_EncryptionContext* ctx = ((PyXmlSec_EncryptionContext*)self); + if (ctx->handle->encKey == NULL) { + Py_RETURN_NONE; + } + PyXmlSec_Key* key = PyXmlSec_NewKey(); - key->handle = ((PyXmlSec_EncryptionContext*)self)->handle->encKey; + key->handle = ctx->handle->encKey; key->is_own = 0; return (PyObject*)key; } @@ -142,9 +149,10 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume xmlNodePtr n = ctx->replacedNodeList; xmlNodePtr nn; while (n != NULL) { + PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; // if n has references, it will not be deleted - Py_XDECREF(PyXmlSec_elementFactory(doc, n)); + Py_DECREF(PyXmlSec_elementFactory(doc, n)); n = nn; } ctx->replacedNodeList = NULL; @@ -290,7 +298,7 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg } xmlNodePtr xparent = node->_c_node->parent; - if (xparent != NULL && !_isElement(xparent)) { + if (xparent != NULL && !PyXmlSec_IsElement(xparent)) { xparent = NULL; } @@ -323,7 +331,7 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg if (!ctx->resultReplaced) { Py_XDECREF(node_num); Py_XDECREF(parent); - PYXMLSEC_DEBUGF("%p: decrypt - ok", self); + PYXMLSEC_DEBUGF("%p: binary.decrypt - ok", self); return PyBytes_FromStringAndSize( (const char*)xmlSecBufferGetData(ctx->result), (Py_ssize_t)xmlSecBufferGetSize(ctx->result) ); @@ -341,7 +349,7 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg parent = tmp; } Py_DECREF(node_num); - PYXMLSEC_DEBUGF("%p: decrypt - ok", self); + PYXMLSEC_DEBUGF("%p: parent.decrypt - ok", self); return parent; } diff --git a/src/exception.c b/src/exception.c index 3de0040d..64caac70 100644 --- a/src/exception.c +++ b/src/exception.c @@ -122,6 +122,7 @@ void PyXmlSec_SetLastError2(PyObject* type, const char* msg) { } } PyErr_SetObject(type, last); + Py_DECREF(last); } void PyXmlSec_SetLastError(const char* msg) { diff --git a/src/keys.c b/src/keys.c index c1ee2cbd..d21507e2 100644 --- a/src/keys.c +++ b/src/keys.c @@ -354,7 +354,11 @@ static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { PyErr_SetString(PyExc_ValueError, "key is not ready"); return NULL; } - return PyString_FromString((const char*)xmlSecKeyGetName(handle)); + const char* cname = (const char*)xmlSecKeyGetName(handle); + if (cname != NULL) { + return PyString_FromString(cname); + } + Py_RETURN_NONE; } static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { @@ -517,6 +521,7 @@ static void PyXmlSec_KeysManager__del__(PyObject* self) { PYXMLSEC_DEBUGF("%p: delete KeysManager", self); PyXmlSec_KeysManager* manager = (PyXmlSec_KeysManager*)self; if (manager->handle != NULL) { + PYXMLSEC_DEBUGF("%p: delete KeysManager handle - %p", self, manager->handle); xmlSecKeysMngrDestroy(manager->handle); } Py_TYPE(self)->tp_free(self); @@ -528,7 +533,7 @@ static const char PyXmlSec_KeysManagerAddKey__doc__[] = \ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "key", NULL}; - PyXmlSec_Key* key; + PyXmlSec_Key* key = NULL; PYXMLSEC_DEBUGF("%p(%p): add key - start", self, ((PyXmlSec_KeysManager*)self)->handle); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:add_key", kwlist, PyXmlSec_KeyType, &key)) { @@ -574,15 +579,18 @@ static const char PyXmlSec_KeysManagerLoadCert__doc__[] = \ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "filename", "format", "type", NULL}; - const char* filename = NULL; + PyObject* filepath = NULL; unsigned int format = 0; unsigned int type = 0; PYXMLSEC_DEBUGF("%p: load cert - start", self); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "sII:load_cert", kwlist, &filename, &format, &type)) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&II:load_cert", kwlist, + PyString_FSConverter, &filepath, &format, &type)) { goto ON_FAIL; } + const char* filename = PyBytes_AsString(filepath); + int rv; Py_BEGIN_ALLOW_THREADS; rv = xmlSecCryptoAppKeysMngrCertLoad(((PyXmlSec_KeysManager*)self)->handle, filename, format, type); @@ -591,10 +599,12 @@ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, Py PyXmlSec_SetLastError("cannot load cert"); goto ON_FAIL; } + Py_DECREF(filepath); PYXMLSEC_DEBUGF("%p: load cert - ok", self); Py_RETURN_NONE; ON_FAIL: PYXMLSEC_DEBUGF("%p: load cert - fail", self); + Py_XDECREF(filepath); return NULL; } diff --git a/src/lxml.c b/src/lxml.c index 3f48135d..862ee682 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -10,6 +10,7 @@ #include "common.h" #include "lxml.h" +#include #include #include @@ -21,6 +22,10 @@ int PyXmlSec_InitLxmlModule(void) { return import_lxml__etree(); } +int PyXmlSec_IsElement(xmlNodePtr xnode) { + return _isElement(xnode); +} + PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr xnode) { return elementFactory(doc, xnode); } diff --git a/src/lxml.h b/src/lxml.h index f5838d67..435ccdff 100644 --- a/src/lxml.h +++ b/src/lxml.h @@ -16,12 +16,13 @@ #include #include -#include #include typedef struct LxmlElement* PyXmlSec_LxmlElementPtr; typedef struct LxmlDocument* PyXmlSec_LxmlDocumentPtr; +// checks that xnode is Element +int PyXmlSec_IsElement(xmlNodePtr xnode); // creates a new element PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xmlNodePtr node); From 3eb882ddd8cfd55c509c62f7f2b649eda9d93d1d Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 4 Jul 2017 12:13:06 +0300 Subject: [PATCH 054/378] Fixed link to examples --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 5d0ecdb2..a1ca111a 100644 --- a/README.rst +++ b/README.rst @@ -15,7 +15,7 @@ Python bindings for the XML Security Library. Usage ****** -Check the `examples `_ to see various examples of signing and verifying using the library. +Check the `examples `_ to see various examples of signing and verifying using the library. ************ Requirements From 5a393ccac9d3ffeef9c9e4c91519914739aa0d85 Mon Sep 17 00:00:00 2001 From: CJWarren Date: Tue, 11 Jul 2017 10:59:30 -0400 Subject: [PATCH 055/378] pkg-config required on mac for proper install (learnwell3) CJs-MacBook-Pro:learnwell cjwarren$ pip install xmlsec Collecting xmlsec Using cached xmlsec-1.1.0.tar.gz Requirement already satisfied: pkgconfig in /Users/cjwarren/.virtualenvs/learnwell3/lib/python3.5/site-packages (from xmlsec) Requirement already satisfied: lxml>=3.0 in /Users/cjwarren/.virtualenvs/learnwell3/lib/python3.5/site-packages (from xmlsec) Building wheels for collected packages: xmlsec Running setup.py bdist_wheel for xmlsec ... error Complete output from command /Users/cjwarren/.virtualenvs/learnwell3/bin/python3.5 -u -c "import setuptools, tokenize;__file__='/private/var/folders/5_/jg5kl6fj1p7gzrsfn7lnm_9c0000gn/T/pip-build-l19z_7fr/xmlsec/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" bdist_wheel -d /var/folders/5_/jg5kl6fj1p7gzrsfn7lnm_9c0000gn/T/tmp43waz_5zpip-wheel- --python-tag cp35: running bdist_wheel running build running build_ext error: pkg-config is not installed ---------------------------------------- Failed building wheel for xmlsec Running setup.py clean for xmlsec Failed to build xmlsec Installing collected packages: xmlsec Running setup.py install for xmlsec ... error Complete output from command /Users/cjwarren/.virtualenvs/learnwell3/bin/python3.5 -u -c "import setuptools, tokenize;__file__='/private/var/folders/5_/jg5kl6fj1p7gzrsfn7lnm_9c0000gn/T/pip-build-l19z_7fr/xmlsec/setup.py';f=getattr(tokenize, 'open', open)(__file__);code=f.read().replace('\r\n', '\n');f.close();exec(compile(code, __file__, 'exec'))" install --record /var/folders/5_/jg5kl6fj1p7gzrsfn7lnm_9c0000gn/T/pip-nw5mysnk-record/install-record.txt --single-version-externally-managed --compile --install-headers /Users/cjwarren/.virtualenvs/learnwell3/bin/../include/site/python3.5/xmlsec: running install running build running build_ext error: pkg-config is not installed --- doc/source/install.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/install.rst b/doc/source/install.rst index 43987710..d94ea755 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -37,6 +37,6 @@ Mac xcode-select --install brew upgrade - brew install libxml2 libxmlsec1 + brew install libxml2 libxmlsec1 pkg-config pip install xmlsec From 01b1f024ed85609fbd2fe11aaa018ff5787c3ace Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 21 Jul 2017 00:57:10 +0100 Subject: [PATCH 056/378] Fix segfault if load key from binary fails --- src/keys.c | 2 +- tests/test_keys.py | 46 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+), 1 deletion(-) diff --git a/src/keys.c b/src/keys.c index d21507e2..f7618296 100644 --- a/src/keys.c +++ b/src/keys.c @@ -253,7 +253,7 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb ON_FAIL: PYXMLSEC_DEBUG("load symmetric key - fail"); Py_XDECREF(key); - Py_DECREF(filepath); + Py_XDECREF(filepath); return NULL; } diff --git a/tests/test_keys.py b/tests/test_keys.py index 081b85d5..d75e44d1 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -13,10 +13,18 @@ def test_key_from_memory(self): key = xmlsec.Key.from_memory(self.load("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) + def test_key_from_memory_with_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.Key.from_memory(1, format="") + def test_key_from_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) + def test_key_from_file_with_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.Key.from_file(1, format="") + def test_key_from_fileobj(self): with open(self.path("rsakey.pem"), "rb") as fobj: key = xmlsec.Key.from_file(fobj, format=consts.KeyDataFormatPem) @@ -26,15 +34,29 @@ def test_generate(self): key = xmlsec.Key.generate(klass=consts.KeyDataAes, size=256, type=consts.KeyDataTypeSession) self.assertIsNotNone(key) + def test_generate_with_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.Key.generate(klass="", size="", type="") + def test_from_binary_file(self): key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path("deskey.bin")) self.assertIsNotNone(key) + def test_from_binary_file_with_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.Key.from_binary_file(klass="", filename=1) + def test_load_cert_from_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) key.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem) + def test_load_cert_from_file_with_bad_args(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with self.assertRaises(TypeError): + key.load_cert_from_file(1, format="") + def test_load_cert_from_fileobj(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) @@ -46,8 +68,15 @@ def test_load_cert_from_memory(self): self.assertIsNotNone(key) key.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem) + def test_load_cert_from_memory_with_bad_args(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with self.assertRaises(TypeError): + key.load_cert_from_memory(1, format="") + def test_name(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNone(key.name) key.name = "rsakey" self.assertEqual("rsakey", key.name) @@ -64,16 +93,33 @@ def test_add_key(self): mngr = xmlsec.KeysManager() mngr.add_key(key) + def test_add_key_with_bad_args(self): + mngr = xmlsec.KeysManager() + with self.assertRaises(TypeError): + mngr.add_key("") + def test_load_cert(self): mngr = xmlsec.KeysManager() mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) mngr.load_cert(self.path("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + def test_load_cert_with_bad_args(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + with self.assertRaises(TypeError): + mngr.load_cert(1, format="", type="") + def test_load_cert_from_memory(self): mngr = xmlsec.KeysManager() mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) mngr.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + def test_load_cert_from_memory_with_bad_args(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + with self.assertRaises(TypeError): + mngr.load_cert_from_memory(1, format="", type="") + def test_load_invalid_key(self): mngr = xmlsec.KeysManager() with self.assertRaises(ValueError): From ace3571048e6342a00efc987c8a6a717dd5e7ec3 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 21 Jul 2017 00:59:34 +0100 Subject: [PATCH 057/378] Add method to load symmetric key from memory --- src/keys.c | 49 ++++++++++++++++++++++++++++++++++++++++++++++ tests/test_keys.py | 8 ++++++++ 2 files changed, 57 insertions(+) diff --git a/src/keys.c b/src/keys.c index f7618296..0d0d0d3e 100644 --- a/src/keys.c +++ b/src/keys.c @@ -257,6 +257,49 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb return NULL; } +static const char PyXmlSec_KeyFromBinaryData__doc__[] = \ + "Loads (symmetric) key of kind *klass* from *data*.\n\n" + ":param klass: the key value data klass\n" + ":param data: the key binary data\n" + ":return: pointer to newly created key\n"; +static PyObject* PyXmlSec_KeyFromBinaryData(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = { "klass", "data", NULL}; + + PyXmlSec_KeyData* keydata = NULL; + const char* data = NULL; + Py_ssize_t data_size = 0; + + PyXmlSec_Key* key = NULL; + + PYXMLSEC_DEBUG("load symmetric key from memory - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!s#:from_binary_data", kwlist, + PyXmlSec_KeyDataType, &keydata, &data, &data_size)) + { + goto ON_FAIL; + } + + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + key->handle = xmlSecKeyReadMemory(keydata->id, (const xmlSecByte*)data, (xmlSecSize)data_size); + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot read key"); + goto ON_FAIL; + } + + key->is_own = 1; + + PYXMLSEC_DEBUG("load symmetric key from memory - ok"); + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("load symmetric key from memory - fail"); + Py_XDECREF(key); + return NULL; +} + static const char PyXmlSec_KeyCertFromMemory__doc__[] = \ "Loads certificate from memory.\n\n" ":param data: the certificate binary data\n" @@ -413,6 +456,12 @@ static PyMethodDef PyXmlSec_KeyMethods[] = { METH_CLASS|METH_VARARGS|METH_KEYWORDS, PyXmlSec_KeyFromBinaryFile__doc__ }, + { + "from_binary_data", + (PyCFunction)PyXmlSec_KeyFromBinaryData, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyFromBinaryData__doc__ + }, { "load_cert_from_memory", (PyCFunction)PyXmlSec_KeyCertFromMemory, diff --git a/tests/test_keys.py b/tests/test_keys.py index d75e44d1..add11e41 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -46,6 +46,14 @@ def test_from_binary_file_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.from_binary_file(klass="", filename=1) + def test_from_binary_data(self): + key = xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=self.load("deskey.bin")) + self.assertIsNotNone(key) + + def test_from_binary_data_with_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.Key.from_binary_data(klass="", data=1) + def test_load_cert_from_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) From 2276d516f36d794d601480208bc91e437561108a Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 21 Jul 2017 01:03:47 +0100 Subject: [PATCH 058/378] Add support to decrypt separated EncryptedKey --- src/enc.c | 42 ++++++++++++++++++++++++++++------------- tests/data/enc3-in.xml | 4 ++++ tests/data/enc3-out.xml | 20 ++++++++++++++++++++ tests/test_enc.py | 20 +++++++++++++++++++- 4 files changed, 72 insertions(+), 14 deletions(-) create mode 100644 tests/data/enc3-in.xml create mode 100644 tests/data/enc3-out.xml diff --git a/src/enc.c b/src/enc.c index 176511d9..258856db 100644 --- a/src/enc.c +++ b/src/enc.c @@ -15,6 +15,7 @@ #include "lxml.h" #include +#include typedef struct { PyObject_HEAD @@ -105,6 +106,18 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi return 0; } +static const char PyXmlSec_EncryptionContextReset__doc__[] = \ + "Resets *context*, user settings are not touched.\n"; +static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) { + PYXMLSEC_DEBUGF("%p: reset context - start", self); + xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; + Py_BEGIN_ALLOW_THREADS; + xmlSecEncCtxReset(ctx); + Py_END_ALLOW_THREADS; + PYXMLSEC_DEBUGF("%p: reset context - ok", self); + Py_RETURN_NONE; +} + static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \ "Encrypts binary *data* according to `EncryptedData` template *template*\n"\ "Note: *template* is modified in place.\n\n" @@ -163,12 +176,9 @@ static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \ "Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\ "(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\ "It must have one of these two values (or an exception is raised).\n"\ - "The operation modifies the tree containing *node* in a way that\n"\ - "`lxml` references to or into this tree may see a surprising state.\n"\ - "You should no longer rely on them. Especially, you should use\n"\ - "`getroottree()` on the result to obtain the encrypted result tree.\n\n" - ":param template: the pointer to template node\n" - ":param node: the pointer to node for encryption\n" + "The operation modifies the tree and removes replaced nodes.\n"\ + ":param template: the pointer to template node\n"\ + ":param node: the pointer to node for encryption\n"\ ":return: the pointer to newly created node\n"; static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "node", NULL}; @@ -273,14 +283,12 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* } static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \ - "Decrypts *node* (an `EncryptedData` element) and return the result.\n"\ + "Decrypts *node* (an `EncryptedData` or `EncryptedKey` element) and return the result.\n"\ "The decryption may result in binary data or an XML subtree.\n"\ "In the former case, the binary data is returned. In the latter case,\n"\ "the input tree is modified and a reference to the decrypted XML subtree is returned.\n"\ - "If the operation modifies the tree, `lxml` references to or into this tree may see a surprising state.\n"\ - "You should no longer rely on them. Especially, you should use `getroottree()` on the result\n"\ - "to obtain the decrypted result tree.\n\n" - ":param node: the pointer to node\n" + "If the operation modifies the tree, it removes replaced nodes.\n"\ + ":param node: the pointer to or node\n" ":return: depends on input parameters\n"; static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) { @@ -310,14 +318,16 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg } // get index of node node_num = PyObject_CallMethod(parent, "index", "O", node); - PYXMLSEC_DEBUGF("%p, %p", parent, node_num); + PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num); } xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; - ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; int rv; Py_BEGIN_ALLOW_THREADS; + ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; + ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData; + PYXMLSEC_DEBUGF("mode: %d", ctx->mode); rv = xmlSecEncCtxDecrypt(ctx, node->_c_node); Py_END_ALLOW_THREADS; @@ -385,6 +395,12 @@ static PyGetSetDef PyXmlSec_EncryptionContextGetSet[] = { }; static PyMethodDef PyXmlSec_EncryptionContextMethods[] = { + { + "reset", + (PyCFunction)PyXmlSec_EncryptionContextReset, + METH_NOARGS, + PyXmlSec_EncryptionContextReset__doc__, + }, { "encrypt_binary", (PyCFunction)PyXmlSec_EncryptionContextEncryptBinary, diff --git a/tests/data/enc3-in.xml b/tests/data/enc3-in.xml new file mode 100644 index 00000000..a2695635 --- /dev/null +++ b/tests/data/enc3-in.xml @@ -0,0 +1,4 @@ + + +test + diff --git a/tests/data/enc3-out.xml b/tests/data/enc3-out.xml new file mode 100644 index 00000000..5289d7e9 --- /dev/null +++ b/tests/data/enc3-out.xml @@ -0,0 +1,20 @@ + + + + + +HJwrfL7kOIB0QaldMJdza1HitpLCjw+eoult1C6yExDXJ09zKaSQER+pUL9Vt5fm +d4Oitsf0CUNkjG1xWJdFsftqUIuvYGnkUNhT0vtqoYbdhJkCcB9cCwvTrww2+VTF +NIasTdechlSD1qQOR8uf6+S94Ae4PVSfWU+5YLTJFpMjR+OT7f6BSbYNv1By6Cko +G39WTSKTRcVDzcMxRepAGb59r508yKIJhwabCf3Opu+Ams7ia7BH4oa4ro9YSWwm +hAJ0CN4a6b5odcRbNvuHcwWSxpoysWKbOROQ0H4xC4nGZeL/AXlpSc8eNuNG+g6D +CTBwsOXCAEJYXPkTrnB3qQ== + + + + + +4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0= + + + diff --git a/tests/test_enc.py b/tests/test_enc.py index c852642a..726520f3 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -87,7 +87,25 @@ def test_decrypt1(self): def test_decrypt2(self): self.check_decrypt(2) - def check_decrypt(self, i, ): + def test_decrypt_key(self): + root = self.load_xml('enc3-out.xml') + enc_key = xmlsec.tree.find_child(root, consts.NodeEncryptedKey, consts.EncNs) + self.assertIsNotNone(enc_key) + + manager = xmlsec.KeysManager() + manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + ctx = xmlsec.EncryptionContext(manager) + keydata = ctx.decrypt(enc_key) + ctx.reset() + root.remove(enc_key) + ctx.key = xmlsec.Key.from_binary_data(consts.KeyDataAes, keydata) + enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs) + self.assertIsNotNone(enc_data) + decrypted = ctx.decrypt(enc_data) + self.assertIsNotNone(decrypted) + self.assertEqual(self.load_xml("enc3-in.xml"), decrypted) + + def check_decrypt(self, i): root = self.load_xml('enc%d-out.xml' % i) enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs) self.assertIsNotNone(enc_data) From 74331b11241629721c8d2d7421d66e76d0ef5c46 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 21 Jul 2017 01:21:00 +0100 Subject: [PATCH 059/378] Fix debug trace --- src/exception.c | 31 +++++++++++++++++++++++++++++-- src/exception.h | 2 ++ src/main.c | 2 +- 3 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/exception.c b/src/exception.c index 64caac70..6e9dce7b 100644 --- a/src/exception.c +++ b/src/exception.c @@ -16,6 +16,8 @@ #include +#include + // default error class PyObject* PyXmlSec_Error; PyObject* PyXmlSec_InternalError; @@ -23,6 +25,8 @@ PyObject* PyXmlSec_VerificationError; static int PyXmlSec_LastErrorKey = 0; +static int PyXmlSec_PrintErrorMessage = 0; + typedef struct { const xmlChar* file; const xmlChar* func; @@ -83,8 +87,27 @@ static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func, // TODO do not allocate error object each time. PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolderCreate(file, line, func, object, subject, reason, msg))); - // also call default callback - xmlSecErrorsDefaultCallback(file, line, func, object, subject, reason, msg); + if (PyXmlSec_PrintErrorMessage) { + const char* error_msg = NULL; + xmlSecSize i; + for (i = 0; (i < XMLSEC_ERRORS_MAX_NUMBER) && (xmlSecErrorsGetMsg(i) != NULL); ++i) { + if(xmlSecErrorsGetCode(i) == reason) { + error_msg = xmlSecErrorsGetMsg(i); + break; + } + } + + fprintf(stderr, + "func=%s:file=%s:line=%d:obj=%s:subj=%s:error=%d:%s:%s\n", + (func != NULL) ? func : "unknown", + (file != NULL) ? file : "unknown", + line, + (object != NULL) ? object : "unknown", + (subject != NULL) ? subject : "unknown", + reason, + (error_msg != NULL) ? error_msg : "", + (msg != NULL) ? msg : ""); + } } // pops the last error which was occurred in current thread @@ -133,6 +156,10 @@ void PyXmlSec_ClearError(void) { PyXmlSec_ErrorHolderFree(PyXmlSec_ExchangeLastError(NULL)); } +void PyXmlSecEnableDebugTrace(int v) { + PyXmlSec_PrintErrorMessage = v; +} + // initializes errors module int PyXmlSec_ExceptionsModule_Init(PyObject* package) { PyXmlSec_Error = NULL; diff --git a/src/exception.h b/src/exception.h index a94216c6..9dea5ecb 100644 --- a/src/exception.h +++ b/src/exception.h @@ -22,4 +22,6 @@ void PyXmlSec_SetLastError2(PyObject* type, const char* msg); void PyXmlSec_ClearError(void); +void PyXmlSecEnableDebugTrace(int); + #endif //__PYXMLSEC_EXCEPTIONS_H__ diff --git a/src/main.c b/src/main.c index 1a0d3729..c9121fa9 100644 --- a/src/main.c +++ b/src/main.c @@ -106,7 +106,7 @@ static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, Py if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:enable_debug_trace", kwlist, &enabled)) { return NULL; } - xmlSecErrorsDefaultCallbackEnableOutput(PyObject_IsTrue(enabled)); + PyXmlSecEnableDebugTrace(PyObject_IsTrue(enabled)); Py_RETURN_NONE; } From 55f670b56535d8e037e4fd380e51d7729ca841cb Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 21 Jul 2017 16:59:04 +0100 Subject: [PATCH 060/378] Add context dump in debug --- src/debug.h | 2 ++ src/ds.c | 11 +++++++---- src/enc.c | 5 +++++ 3 files changed, 14 insertions(+), 4 deletions(-) diff --git a/src/debug.h b/src/debug.h index 0604a462..3f851bdc 100644 --- a/src/debug.h +++ b/src/debug.h @@ -15,9 +15,11 @@ #include #define PYXMLSEC_DEBUG(fmt) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__) #define PYXMLSEC_DEBUGF(fmt, ...) fprintf(stderr, "[%s:%d %s] " fmt "\n", __FILE__, __LINE__, __FUNCTION__, __VA_ARGS__) +#define PYXMLSEC_DUMP(method, obj) method(obj, stderr) #else #define PYXMLSEC_DEBUG(...) #define PYXMLSEC_DEBUGF(...) +#define PYXMLSEC_DUMP(method, obj) #endif // PYXMLSEC_ENABLE_DEBUG #endif // __PYXMLSEC_DEBUG_H__ diff --git a/src/ds.c b/src/ds.c index 70499543..b6bf4152 100644 --- a/src/ds.c +++ b/src/ds.c @@ -172,9 +172,11 @@ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, P goto ON_FAIL; } + xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxSign(((PyXmlSec_SignatureContext*)self)->handle, node->_c_node); + rv = xmlSecDSigCtxSign(ctx, node->_c_node); + PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("failed to sign"); @@ -202,17 +204,18 @@ static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, goto ON_FAIL; } - xmlSecDSigCtxPtr handle = ((PyXmlSec_SignatureContext*)self)->handle; + xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxVerify(handle, node->_c_node); + rv = xmlSecDSigCtxVerify(ctx, node->_c_node); + PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("failed to verify"); goto ON_FAIL; } - if (handle->status != xmlSecDSigStatusSucceeded) { + if (ctx->status != xmlSecDSigStatusSucceeded) { PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid."); goto ON_FAIL; } diff --git a/src/enc.c b/src/enc.c index 258856db..2362ad69 100644 --- a/src/enc.c +++ b/src/enc.c @@ -113,6 +113,7 @@ static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; Py_BEGIN_ALLOW_THREADS; xmlSecEncCtxReset(ctx); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); Py_END_ALLOW_THREADS; PYXMLSEC_DEBUGF("%p: reset context - ok", self); Py_RETURN_NONE; @@ -141,6 +142,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec int rv; Py_BEGIN_ALLOW_THREADS; rv = xmlSecEncCtxBinaryEncrypt(ctx, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -226,6 +228,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* xnew_node = NULL; } } + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); Py_END_ALLOW_THREADS; PyXmlSec_ClearReplacedNodes(ctx, node->_doc); @@ -268,6 +271,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* int rv; Py_BEGIN_ALLOW_THREADS; rv = xmlSecEncCtxUriEncrypt(ctx, template->_c_node, (const xmlSecByte*)uri); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -329,6 +333,7 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData; PYXMLSEC_DEBUGF("mode: %d", ctx->mode); rv = xmlSecEncCtxDecrypt(ctx, node->_c_node); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); Py_END_ALLOW_THREADS; PyXmlSec_ClearReplacedNodes(ctx, node->_doc); From 83e360cc9c586454c990b1479ec6a766f2148cc0 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 10 Aug 2017 01:27:50 +0300 Subject: [PATCH 061/378] fix build for vs2008 --- src/common.h | 4 -- src/constants.c | 8 ++-- src/ds.c | 107 ++++++++++++++++++++++++++---------------------- src/enc.c | 97 ++++++++++++++++++++++++------------------- src/exception.c | 11 +++-- src/keys.c | 82 ++++++++++++++++++++++--------------- src/main.c | 7 +++- src/template.c | 57 ++++++++++++++++---------- src/tree.c | 20 +++++---- src/utils.c | 17 +++++--- 10 files changed, 242 insertions(+), 168 deletions(-) diff --git a/src/common.h b/src/common.h index 5f91bc2f..243ed651 100644 --- a/src/common.h +++ b/src/common.h @@ -16,10 +16,6 @@ #define MODULE_NAME "xmlsec" #endif -#ifndef MODULE_DOC -#define MODULE_DOC "The tiny python wrapper around xmlsec1 library." -#endif - #define JOIN(X,Y) DO_JOIN1(X,Y) #define DO_JOIN1(X,Y) DO_JOIN2(X,Y) #define DO_JOIN2(X,Y) X##Y diff --git a/src/constants.c b/src/constants.c index e4f3e440..81f94560 100644 --- a/src/constants.c +++ b/src/constants.c @@ -103,9 +103,9 @@ static PyTypeObject _PyXmlSec_TransformType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ 0, /* tp_new */ - PyObject_Del /* tp_free */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_TransformType = &_PyXmlSec_TransformType; @@ -197,9 +197,9 @@ static PyTypeObject _PyXmlSec_KeyDataType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ 0, /* tp_new */ - PyObject_Del /* tp_free */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_KeyDataType = &_PyXmlSec_KeyDataType; diff --git a/src/ds.c b/src/ds.c index b6bf4152..5986f566 100644 --- a/src/ds.c +++ b/src/ds.c @@ -34,10 +34,10 @@ static PyObject* PyXmlSec_SignatureContext__new__(PyTypeObject *type, PyObject * static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "manager", NULL}; - + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_KeysManager* manager = NULL; + PYXMLSEC_DEBUGF("%p: init sign context", self); - PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { goto ON_FAIL; } @@ -47,6 +47,7 @@ static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyO goto ON_FAIL; } ctx->manager = manager; + PYXMLSEC_DEBUGF("%p: signMethod: %p", self, ctx->handle->signMethod); PYXMLSEC_DEBUGF("%p: init sign context - ok, manager - %p", self, manager); return 0; ON_FAIL: @@ -56,8 +57,8 @@ static int PyXmlSec_SignatureContext__init__(PyObject* self, PyObject* args, PyO } static void PyXmlSec_SignatureContext__del__(PyObject* self) { - PYXMLSEC_DEBUGF("%p: delete sign context", self); PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; + PYXMLSEC_DEBUGF("%p: delete sign context", self); if (ctx->handle != NULL) { xmlSecDSigCtxDestroy(ctx->handle); } @@ -69,29 +70,33 @@ static void PyXmlSec_SignatureContext__del__(PyObject* self) { static const char PyXmlSec_SignatureContextKey__doc__[] = "Signature key.\n"; static PyObject* PyXmlSec_SignatureContextKeyGet(PyObject* self, void* closure) { PyXmlSec_SignatureContext* ctx = ((PyXmlSec_SignatureContext*)self); + PyXmlSec_Key* key; + if (ctx->handle->signKey == NULL) { Py_RETURN_NONE; } - PyXmlSec_Key* key = PyXmlSec_NewKey(); + key = PyXmlSec_NewKey(); key->handle = ctx->handle->signKey; key->is_own = 0; return (PyObject*)key; } static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void* closure) { + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; + PyXmlSec_Key* key; + PYXMLSEC_DEBUGF("%p, %p", self, value); if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); return -1; } - PyXmlSec_Key* key = (PyXmlSec_Key*)value; + key = (PyXmlSec_Key*)value; if (key->handle == NULL) { PyErr_SetString(PyExc_TypeError, "empty key."); return -1; } - PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; if (ctx->handle->signKey != NULL) { xmlSecKeyDestroy(ctx->handle->signKey); } @@ -117,7 +122,8 @@ static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* a const char* id_ns = NULL; xmlChar* name = NULL; - xmlAttrPtr attr = NULL; + xmlAttrPtr attr; + xmlAttrPtr tmpAttr; PYXMLSEC_DEBUGF("%p: register id - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|sz:register_id", kwlist, @@ -138,7 +144,7 @@ static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* a } name = xmlNodeListGetString(node->_c_node->doc, attr->children, 1); - xmlAttrPtr tmpAttr = xmlGetID(node->_c_node->doc, name); + tmpAttr = xmlGetID(node->_c_node->doc, name); if (tmpAttr != attr) { if (tmpAttr != NULL) { PyErr_SetString(PyXmlSec_Error, "duplicated id."); @@ -165,18 +171,18 @@ static const char PyXmlSec_SignatureContextSign__doc__[] = \ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_LxmlElementPtr node = NULL; + int rv; PYXMLSEC_DEBUGF("%p: sign - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:sign", kwlist, PyXmlSec_LxmlElementConverter, &node)) { goto ON_FAIL; } - xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxSign(ctx, node->_c_node); - PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx); + rv = xmlSecDSigCtxSign(ctx->handle, node->_c_node); + PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("failed to sign"); @@ -197,25 +203,25 @@ static const char PyXmlSec_SignatureContextVerify__doc__[] = \ static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_LxmlElementPtr node = NULL; + int rv; PYXMLSEC_DEBUGF("%p: verify - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:verify", kwlist, PyXmlSec_LxmlElementConverter, &node)) { goto ON_FAIL; } - xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxVerify(ctx, node->_c_node); - PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx); + rv = xmlSecDSigCtxVerify(ctx->handle, node->_c_node); + PYXMLSEC_DUMP(xmlSecDSigCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("failed to verify"); goto ON_FAIL; } - if (ctx->status != xmlSecDSigStatusSucceeded) { + if (ctx->handle->status != xmlSecDSigStatusSucceeded) { PyErr_SetString(PyXmlSec_VerificationError, "Signature is invalid."); goto ON_FAIL; } @@ -227,54 +233,55 @@ static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, } // common helper for operations binary_verify and binary_sign -static int PyXmlSec_ProcessSignBinary(xmlSecDSigCtxPtr ctx, const xmlSecByte* data, xmlSecSize data_size, xmlSecTransformId method) { +static int PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext* ctx, const xmlSecByte* data, xmlSecSize data_size, xmlSecTransformId method) { + int rv; + if (!(method->usage & xmlSecTransformUsageSignatureMethod)) { PyErr_SetString(PyXmlSec_Error, "incompatible signature method"); return -1; } - if (ctx->signKey == NULL) { + if (ctx->handle->signKey == NULL) { PyErr_SetString(PyXmlSec_Error, "Sign key is not specified."); } - if (ctx->signMethod != NULL) { + if (ctx->handle->signMethod != NULL) { + PYXMLSEC_DEBUGF("%p: signMethod: %p", ctx, ctx->handle->signMethod); PyErr_SetString(PyXmlSec_Error, "Signature context already used; it is designed for one use only."); return -1; } - ctx->signMethod = xmlSecTransformCtxCreateAndAppend(&(ctx->transformCtx), method); - if (ctx->signMethod == NULL) { + ctx->handle->signMethod = xmlSecTransformCtxCreateAndAppend(&(ctx->handle->transformCtx), method); + if (ctx->handle->signMethod == NULL) { PyXmlSec_SetLastError("could not create signature transform."); return -1; } - int rv; - - ctx->signMethod->operation = ctx->operation; - xmlSecTransformSetKeyReq(ctx->signMethod, &(ctx->keyInfoReadCtx.keyReq)); - rv = xmlSecKeyMatch(ctx->signKey, NULL, &(ctx->keyInfoReadCtx.keyReq)); + ctx->handle->signMethod->operation = ctx->handle->operation; + xmlSecTransformSetKeyReq(ctx->handle->signMethod, &(ctx->handle->keyInfoReadCtx.keyReq)); + rv = xmlSecKeyMatch(ctx->handle->signKey, NULL, &(ctx->handle->keyInfoReadCtx.keyReq)); if (rv != 1) { PyXmlSec_SetLastError("inappropriate key type."); return -1; } - rv = xmlSecTransformSetKey(ctx->signMethod, ctx->signKey); + rv = xmlSecTransformSetKey(ctx->handle->signMethod, ctx->handle->signKey); if (rv < 0) { PyXmlSec_SetLastError("cannot set key."); return -1; } - ctx->transformCtx.result = NULL; - ctx->transformCtx.status = xmlSecTransformStatusNone; + ctx->handle->transformCtx.result = NULL; + ctx->handle->transformCtx.status = xmlSecTransformStatusNone; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecTransformCtxBinaryExecute(&(ctx->transformCtx), data, data_size); + rv = xmlSecTransformCtxBinaryExecute(&(ctx->handle->transformCtx), data, data_size); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("failed to transform."); return -1; } - ctx->result = ctx->transformCtx.result; + ctx->handle->result = ctx->handle->transformCtx.result; return 0; } @@ -286,7 +293,7 @@ static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \ ":return: the signature\n"; static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", NULL}; - + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_Transform* transform = NULL; const char* data = NULL; Py_ssize_t data_size = 0; @@ -298,8 +305,7 @@ static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* a goto ON_FAIL; } - xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; - ctx->operation = xmlSecTransformOperationSign; + ctx->handle->operation = xmlSecTransformOperationSign; if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) { goto ON_FAIL; @@ -307,7 +313,8 @@ static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* a PYXMLSEC_DEBUGF("%p: sign_binary - ok", self); return PyBytes_FromStringAndSize( - (const char*)xmlSecBufferGetData(ctx->result), (Py_ssize_t)xmlSecBufferGetSize(ctx->result) + (const char*)xmlSecBufferGetData(ctx->handle->result), + (Py_ssize_t)xmlSecBufferGetSize(ctx->handle->result) ); ON_FAIL: PYXMLSEC_DEBUGF("%p: sign_binary - fail", self); @@ -323,11 +330,13 @@ static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \ static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", "signature", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_Transform* transform = NULL; const char* data = NULL; Py_ssize_t data_size = 0; const char* sign = NULL; Py_ssize_t sign_size = 0; + int rv; PYXMLSEC_DEBUGF("%p: verify binary - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#O!s#:verify_binary", kwlist, @@ -336,15 +345,13 @@ static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* goto ON_FAIL; } - xmlSecDSigCtxPtr ctx = ((PyXmlSec_SignatureContext*)self)->handle; - ctx->operation = xmlSecTransformOperationVerify; + ctx->handle->operation = xmlSecTransformOperationVerify; if (PyXmlSec_ProcessSignBinary(ctx, (const xmlSecByte*)data, (xmlSecSize)data_size, transform->id) != 0) { goto ON_FAIL; } - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecTransformVerify(ctx->signMethod, (const xmlSecByte*)sign, (xmlSecSize)sign_size, &(ctx->transformCtx)); + rv = xmlSecTransformVerify(ctx->handle->signMethod, (const xmlSecByte*)sign, (xmlSecSize)sign_size, &(ctx->handle->transformCtx)); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -352,7 +359,7 @@ static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* goto ON_FAIL; } - if (ctx->signMethod->status != xmlSecTransformStatusOk) { + if (ctx->handle->signMethod->status != xmlSecTransformStatusOk) { PyXmlSec_SetLastError2(PyXmlSec_VerificationError, "Signature is invalid."); goto ON_FAIL; } @@ -372,7 +379,9 @@ static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \ static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_Transform* transform = NULL; + int rv; PYXMLSEC_DEBUGF("%p: enable_reference_transform - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_reference_transform", kwlist, PyXmlSec_TransformType, &transform)) @@ -380,9 +389,8 @@ static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* sel goto ON_FAIL; } - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxEnableReferenceTransform(((PyXmlSec_SignatureContext*)self)->handle, transform->id); + rv = xmlSecDSigCtxEnableReferenceTransform(ctx->handle, transform->id); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -405,16 +413,17 @@ static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \ static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyXmlSec_Transform* transform = NULL; + int rv; PYXMLSEC_DEBUGF("%p: enable_signature_transform - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:enable_signature_transform", kwlist, PyXmlSec_TransformType, &transform)) { goto ON_FAIL; } - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecDSigCtxEnableSignatureTransform(((PyXmlSec_SignatureContext*)self)->handle, transform->id); + rv = xmlSecDSigCtxEnableSignatureTransform(ctx->handle, transform->id); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -435,9 +444,11 @@ static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \ static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "keydata_list", NULL}; + PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; PyObject* keydata_list = NULL; PyObject* iter = NULL; PyObject* item = NULL; + xmlSecPtrListPtr enabled_list; PYXMLSEC_DEBUGF("%p: set_enabled_key_data - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O:set_enabled_key_data", kwlist, &keydata_list)) { @@ -445,7 +456,7 @@ static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyOb } if ((iter = PyObject_GetIter(keydata_list)) == NULL) goto ON_FAIL; - xmlSecPtrListPtr enabled_list = &(((PyXmlSec_SignatureContext*)self)->handle->keyInfoReadCtx.enabledKeyData); + enabled_list = &(ctx->handle->keyInfoReadCtx.enabledKeyData); xmlSecPtrListEmpty(enabled_list); while ((item = PyIter_Next(iter)) != NULL) { @@ -571,9 +582,9 @@ static PyTypeObject _PyXmlSec_SignatureContextType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ PyXmlSec_SignatureContext__init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ PyXmlSec_SignatureContext__new__, /* tp_new */ - PyObject_Del /* tp_free */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_SignatureContextType = &_PyXmlSec_SignatureContextType; diff --git a/src/enc.c b/src/enc.c index 2362ad69..bb5a6833 100644 --- a/src/enc.c +++ b/src/enc.c @@ -38,6 +38,7 @@ static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, Py PyXmlSec_KeysManager* manager = NULL; PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + PYXMLSEC_DEBUGF("%p: init enc context", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O&:__init__", kwlist, PyXmlSec_KeysManagerConvert, &manager)) { goto ON_FAIL; @@ -57,8 +58,10 @@ static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, Py } static void PyXmlSec_EncryptionContext__del__(PyObject* self) { - PYXMLSEC_DEBUGF("%p: delete enc context", self); PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + + PYXMLSEC_DEBUGF("%p: delete enc context", self); + if (ctx->handle != NULL) { xmlSecEncCtxDestroy(ctx->handle); } @@ -70,35 +73,39 @@ static void PyXmlSec_EncryptionContext__del__(PyObject* self) { static const char PyXmlSec_EncryptionContextKey__doc__[] = "Encryption key.\n"; static PyObject* PyXmlSec_EncryptionContextKeyGet(PyObject* self, void* closure) { PyXmlSec_EncryptionContext* ctx = ((PyXmlSec_EncryptionContext*)self); + PyXmlSec_Key* key; + if (ctx->handle->encKey == NULL) { Py_RETURN_NONE; } - PyXmlSec_Key* key = PyXmlSec_NewKey(); + key = PyXmlSec_NewKey(); key->handle = ctx->handle->encKey; key->is_own = 0; return (PyObject*)key; } static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, void* closure) { + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + PyXmlSec_Key* key; + PYXMLSEC_DEBUGF("%p, %p", self, value); if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); return -1; } - xmlSecKeyPtr keyHandle = ((PyXmlSec_Key*)value)->handle; - if (keyHandle == NULL) { + key = (PyXmlSec_Key*)value; + if (key->handle == NULL) { PyErr_SetString(PyExc_TypeError, "empty key."); return -1; } - PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; if (ctx->handle->encKey != NULL) { xmlSecKeyDestroy(ctx->handle->encKey); } - ctx->handle->encKey = xmlSecKeyDuplicate(keyHandle); + ctx->handle->encKey = xmlSecKeyDuplicate(key->handle); if (ctx->handle->encKey == NULL) { PyXmlSec_SetLastError("failed to duplicate key"); return -1; @@ -109,11 +116,12 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi static const char PyXmlSec_EncryptionContextReset__doc__[] = \ "Resets *context*, user settings are not touched.\n"; static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) { + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; + PYXMLSEC_DEBUGF("%p: reset context - start", self); - xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; Py_BEGIN_ALLOW_THREADS; - xmlSecEncCtxReset(ctx); - PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); + xmlSecEncCtxReset(ctx->handle); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; PYXMLSEC_DEBUGF("%p: reset context - ok", self); Py_RETURN_NONE; @@ -128,9 +136,11 @@ static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "data", NULL}; + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; PyXmlSec_LxmlElementPtr template = NULL; const char* data = NULL; Py_ssize_t data_size = 0; + int rv; PYXMLSEC_DEBUGF("%p: encrypt_binary - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s#:encrypt_binary", kwlist, @@ -138,11 +148,10 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec { goto ON_FAIL; } - xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; - int rv; + Py_BEGIN_ALLOW_THREADS; - rv = xmlSecEncCtxBinaryEncrypt(ctx, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size); - PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); + rv = xmlSecEncCtxBinaryEncrypt(ctx->handle, template->_c_node, (const xmlSecByte*)data, (xmlSecSize)data_size); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -163,6 +172,7 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume // release the replaced nodes in a way safe for `lxml` xmlNodePtr n = ctx->replacedNodeList; xmlNodePtr nn; + while (n != NULL) { PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; @@ -185,10 +195,12 @@ static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "node", NULL}; + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; PyXmlSec_LxmlElementPtr template = NULL; PyXmlSec_LxmlElementPtr node = NULL; xmlNodePtr xnew_node = NULL; xmlChar* tmpType = NULL; + int rv = 0; PYXMLSEC_DEBUGF("%p: encrypt_xml - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O&:encrypt_xml", kwlist, @@ -206,9 +218,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* // at `node._c_node` or its children by an extended subtree rooted at "c_node". // We set `XMLSEC_ENC_RETURN_REPLACED_NODE` to prevent deallocation // of the replaced node. This is important as `node` is still referencing it - xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; - ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; - int rv = 0; + ctx->handle->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; // try to do all actions whithin single python-free section // rv has the following codes, 1 - failed to copy node, -1 - op failed, 0 - success @@ -221,17 +231,17 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* rv = 1; } } - if (rv == 0 && xmlSecEncCtxXmlEncrypt(ctx, xnew_node != NULL ? xnew_node: template->_c_node, node->_c_node) < 0) { + if (rv == 0 && xmlSecEncCtxXmlEncrypt(ctx->handle, xnew_node != NULL ? xnew_node: template->_c_node, node->_c_node) < 0) { rv = -1; if (xnew_node != NULL) { xmlFreeNode(xnew_node); xnew_node = NULL; } } - PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; - PyXmlSec_ClearReplacedNodes(ctx, node->_doc); + PyXmlSec_ClearReplacedNodes(ctx->handle, node->_doc); if (rv != 0) { if (rv > 0) { @@ -259,19 +269,19 @@ static const char PyXmlSec_EncryptionContextEncryptUri__doc__[] = \ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "uri", NULL}; + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; PyXmlSec_LxmlElementPtr template = NULL; const char* uri = NULL; + int rv; PYXMLSEC_DEBUGF("%p: encrypt_uri - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s:encrypt_uri", kwlist, PyXmlSec_LxmlElementConverter, &template, &uri)) { goto ON_FAIL; } - xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecEncCtxUriEncrypt(ctx, template->_c_node, (const xmlSecByte*)uri); - PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); + rv = xmlSecEncCtxUriEncrypt(ctx->handle, template->_c_node, (const xmlSecByte*)uri); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; if (rv < 0) { @@ -298,18 +308,25 @@ static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; + PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; PyXmlSec_LxmlElementPtr node = NULL; PyObject* node_num = NULL; PyObject* parent = NULL; + PyObject* tmp; + xmlNodePtr root; + xmlNodePtr xparent; + int rv; + xmlChar* ttype; + int notContent; PYXMLSEC_DEBUGF("%p: decrypt - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:decrypt", kwlist, PyXmlSec_LxmlElementConverter, &node)) { goto ON_FAIL; } - xmlNodePtr xparent = node->_c_node->parent; + xparent = node->_c_node->parent; if (xparent != NULL && !PyXmlSec_IsElement(xparent)) { xparent = NULL; } @@ -325,40 +342,38 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg PYXMLSEC_DEBUGF("parent: %p, %p", parent, node_num); } - xmlSecEncCtxPtr ctx = ((PyXmlSec_EncryptionContext*)self)->handle; - int rv; - Py_BEGIN_ALLOW_THREADS; - ctx->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; - ctx->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData; - PYXMLSEC_DEBUGF("mode: %d", ctx->mode); - rv = xmlSecEncCtxDecrypt(ctx, node->_c_node); - PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx); + ctx->handle->flags = XMLSEC_ENC_RETURN_REPLACED_NODE; + ctx->handle->mode = xmlSecCheckNodeName(node->_c_node, xmlSecNodeEncryptedKey, xmlSecEncNs) ? xmlEncCtxModeEncryptedKey : xmlEncCtxModeEncryptedData; + PYXMLSEC_DEBUGF("mode: %d", ctx->handle->mode); + rv = xmlSecEncCtxDecrypt(ctx->handle, node->_c_node); + PYXMLSEC_DUMP(xmlSecEncCtxDebugDump, ctx->handle); Py_END_ALLOW_THREADS; - PyXmlSec_ClearReplacedNodes(ctx, node->_doc); + PyXmlSec_ClearReplacedNodes(ctx->handle, node->_doc); if (rv < 0) { PyXmlSec_SetLastError("failed to decrypt"); goto ON_FAIL; } - if (!ctx->resultReplaced) { + if (!ctx->handle->resultReplaced) { Py_XDECREF(node_num); Py_XDECREF(parent); PYXMLSEC_DEBUGF("%p: binary.decrypt - ok", self); return PyBytes_FromStringAndSize( - (const char*)xmlSecBufferGetData(ctx->result), (Py_ssize_t)xmlSecBufferGetSize(ctx->result) + (const char*)xmlSecBufferGetData(ctx->handle->result), + (Py_ssize_t)xmlSecBufferGetSize(ctx->handle->result) ); } if (xparent != NULL) { - xmlChar* ttype = xmlGetProp(node->_c_node, XSTR("Type")); - int notContent = (ttype == NULL || !xmlStrEqual(ttype, xmlSecTypeEncContent)); + ttype = xmlGetProp(node->_c_node, XSTR("Type")); + notContent = (ttype == NULL || !xmlStrEqual(ttype, xmlSecTypeEncContent)); xmlFree(ttype); if (notContent) { - PyObject* tmp = PyObject_GetItem(parent, node_num); + tmp = PyObject_GetItem(parent, node_num); if (tmp == NULL) goto ON_FAIL; Py_DECREF(parent); parent = tmp; @@ -369,7 +384,7 @@ static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* arg } // root has been replaced - xmlNodePtr root = xmlDocGetRootElement(node->_doc->_c_doc); + root = xmlDocGetRootElement(node->_doc->_c_doc); if (root == NULL) { PyErr_SetString(PyXmlSec_Error, "decryption resulted in a non well formed document"); goto ON_FAIL; @@ -470,9 +485,9 @@ static PyTypeObject _PyXmlSec_EncryptionContextType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ PyXmlSec_EncryptionContext__init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ PyXmlSec_EncryptionContext__new__, /* tp_new */ - PyObject_Del /* tp_free */ + 0 /* tp_free */ }; PyTypeObject* PyXmlSec_EncryptionContextType = &_PyXmlSec_EncryptionContextType; diff --git a/src/exception.c b/src/exception.c index 6e9dce7b..2ca5ab57 100644 --- a/src/exception.c +++ b/src/exception.c @@ -68,6 +68,9 @@ void PyXmlSec_ErrorHolderFree(PyXmlSec_ErrorHolder* h) { // saves new error in TLS and returns previous static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) { + PyXmlSec_ErrorHolder* v; + int r; + if (PyXmlSec_LastErrorKey == 0) { PYXMLSEC_DEBUG("WARNING: There is no error key."); PyXmlSec_ErrorHolderFree(e); @@ -75,9 +78,9 @@ static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) } // get_key_value and set_key_value are gil free - PyXmlSec_ErrorHolder* v = (PyXmlSec_ErrorHolder*)PyThread_get_key_value(PyXmlSec_LastErrorKey); + v = (PyXmlSec_ErrorHolder*)PyThread_get_key_value(PyXmlSec_LastErrorKey); PyThread_delete_key_value(PyXmlSec_LastErrorKey); - int r = PyThread_set_key_value(PyXmlSec_LastErrorKey, (void*)e); + r = PyThread_set_key_value(PyXmlSec_LastErrorKey, (void*)e); PYXMLSEC_DEBUGF("set_key_value returns %d", r); return v; } @@ -114,11 +117,13 @@ static void PyXmlSec_ErrorCallback(const char* file, int line, const char* func, // the gil should be acquired static PyObject* PyXmlSec_GetLastError(PyObject* type, const char* msg) { PyXmlSec_ErrorHolder* h = PyXmlSec_ExchangeLastError(NULL); + PyObject* exc; + if (h == NULL) { return NULL; } - PyObject* exc = PyObject_CallFunction(type, "is", h->reason, msg); + exc = PyObject_CallFunction(type, "is", h->reason, msg); if (exc == NULL) goto ON_FAIL; PyXmlSec_SetLongAttr(exc, "code", h->reason); diff --git a/src/keys.c b/src/keys.c index 0d0d0d3e..01d7fa30 100644 --- a/src/keys.c +++ b/src/keys.c @@ -27,8 +27,8 @@ static PyObject* PyXmlSec_Key__new__(PyTypeObject *type, PyObject *args, PyObjec } static void PyXmlSec_Key__del__(PyObject* self) { - PYXMLSEC_DEBUGF("%p: delete key", self); PyXmlSec_Key* key = (PyXmlSec_Key*)self; + PYXMLSEC_DEBUGF("%p: delete key", self); if (key->is_own) { PYXMLSEC_DEBUGF("%p: delete handle - %p", self, key->handle); xmlSecKeyDestroy(key->handle); @@ -41,10 +41,12 @@ static PyXmlSec_Key* PyXmlSec_NewKey1(PyTypeObject* type) { } static PyObject* PyXmlSec_Key__copy__(PyObject* self) { + xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; + PyXmlSec_Key* key2; + PYXMLSEC_DEBUGF("%p: copy key", self); - xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; - PyXmlSec_Key* key2 = PyXmlSec_NewKey1(Py_TYPE(self)); + key2 = PyXmlSec_NewKey1(Py_TYPE(self)); if (handle == NULL || key2 == NULL) { PYXMLSEC_DEBUGF("%p: null key", self); @@ -223,6 +225,7 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb PyObject* filepath = NULL; PyXmlSec_Key* key = NULL; + const char* filename; PYXMLSEC_DEBUG("load symmetric key - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&:from_binary_file", kwlist, @@ -231,7 +234,7 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb goto ON_FAIL; } - const char* filename = PyBytes_AsString(filepath); + filename = PyBytes_AsString(filepath); if (filename == NULL) goto ON_FAIL; if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; @@ -307,19 +310,19 @@ static const char PyXmlSec_KeyCertFromMemory__doc__[] = \ static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", NULL}; + PyXmlSec_Key* key = (PyXmlSec_Key*)self; const char* data = NULL; Py_ssize_t data_size = 0; unsigned int format = 0; PyObject* tmp = NULL; + int rv = 0; PYXMLSEC_DEBUGF("%p: load certificate from memory - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#I:load_cert_from_memory", kwlist, &data, &data_size, &format)) { goto ON_FAIL; } - PyXmlSec_Key* key = (PyXmlSec_Key*)self; - int rv = 0; Py_BEGIN_ALLOW_THREADS; rv = xmlSecCryptoAppKeyCertLoadMemory(key->handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format); Py_END_ALLOW_THREADS; @@ -343,6 +346,8 @@ static const char PyXmlSec_KeyCertFromFile__doc__[] = \ static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "file", "format", NULL}; + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + PyObject* file = NULL; unsigned int format = 0; @@ -350,6 +355,7 @@ static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObje int is_content = 0; const char* data = NULL; Py_ssize_t data_size = 0; + int rv = 0; PYXMLSEC_DEBUGF("%p: load certificate from memory - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OI:load_cert_from_file", kwlist, &file, &format)) { @@ -366,8 +372,6 @@ static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObje if (data == NULL) goto ON_FAIL; - PyXmlSec_Key* key = (PyXmlSec_Key*)self; - int rv = 0; Py_BEGIN_ALLOW_THREADS; if (is_content) { rv = xmlSecCryptoAppKeyCertLoadMemory(key->handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format); @@ -391,13 +395,15 @@ static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObje static const char PyXmlSec_KeyName__doc__[] = "the name of *key*.\n"; static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + const char* cname; + PYXMLSEC_DEBUGF("%p: get name of key", self); - xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; - if (handle == NULL) { + if (key->handle == NULL) { PyErr_SetString(PyExc_ValueError, "key is not ready"); return NULL; } - const char* cname = (const char*)xmlSecKeyGetName(handle); + cname = (const char*)xmlSecKeyGetName(key->handle); if (cname != NULL) { return PyString_FromString(cname); } @@ -405,18 +411,20 @@ static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { } static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { + PyXmlSec_Key* key = (PyXmlSec_Key*)self; + const char* name; + PYXMLSEC_DEBUGF("%p: set name of key %p", self, value); - xmlSecKeyPtr handle = ((PyXmlSec_Key*)self)->handle; - if (handle == NULL) { + if (key->handle == NULL) { PyErr_SetString(PyExc_ValueError, "key is not ready"); return -1; } - const char* name = PyString_AsString(value); + name = PyString_AsString(value); if (name == NULL) return -1; - xmlSecKeySetName(handle, XSTR(name)); + xmlSecKeySetName(key->handle, XSTR(name)); return 0; } @@ -526,9 +534,9 @@ static PyTypeObject _PyXmlSec_KeyType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ 0, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ PyXmlSec_Key__new__, /* tp_new */ - PyObject_Del /* tp_free */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_KeyType = &_PyXmlSec_KeyType; @@ -550,8 +558,9 @@ static PyObject* PyXmlSec_KeysManager__new__(PyTypeObject *type, PyObject *args, } static int PyXmlSec_KeysManager__init__(PyObject* self, PyObject* args, PyObject* kwargs) { - PYXMLSEC_DEBUGF("%p: init key manager", self); xmlSecKeysMngrPtr handle = xmlSecKeysMngrCreate(); + + PYXMLSEC_DEBUGF("%p: init key manager", self); if (handle == NULL) { PyXmlSec_SetLastError("failed to create xmlsecKeyManger"); return -1; @@ -567,11 +576,13 @@ static int PyXmlSec_KeysManager__init__(PyObject* self, PyObject* args, PyObject } static void PyXmlSec_KeysManager__del__(PyObject* self) { + PyXmlSec_KeysManager* mgr = (PyXmlSec_KeysManager*)self; + PYXMLSEC_DEBUGF("%p: delete KeysManager", self); - PyXmlSec_KeysManager* manager = (PyXmlSec_KeysManager*)self; - if (manager->handle != NULL) { - PYXMLSEC_DEBUGF("%p: delete KeysManager handle - %p", self, manager->handle); - xmlSecKeysMngrDestroy(manager->handle); + + if (mgr->handle != NULL) { + PYXMLSEC_DEBUGF("%p: delete KeysManager handle - %p", self, mgr->handle); + xmlSecKeysMngrDestroy(mgr->handle); } Py_TYPE(self)->tp_free(self); } @@ -582,7 +593,10 @@ static const char PyXmlSec_KeysManagerAddKey__doc__[] = \ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "key", NULL}; + PyXmlSec_KeysManager* mgr = (PyXmlSec_KeysManager*)self; PyXmlSec_Key* key = NULL; + xmlSecKeyPtr key2; + int rv; PYXMLSEC_DEBUGF("%p(%p): add key - start", self, ((PyXmlSec_KeysManager*)self)->handle); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!:add_key", kwlist, PyXmlSec_KeyType, &key)) { @@ -594,7 +608,6 @@ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyOb goto ON_FAIL; } - xmlSecKeyPtr key2; Py_BEGIN_ALLOW_THREADS key2 = xmlSecKeyDuplicate(key->handle); Py_END_ALLOW_THREADS; @@ -604,9 +617,8 @@ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyOb goto ON_FAIL; } - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecCryptoAppDefaultKeysMngrAdoptKey(((PyXmlSec_KeysManager*)self)->handle, key2); + rv = xmlSecCryptoAppDefaultKeysMngrAdoptKey(mgr->handle, key2); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("cannot add key"); @@ -628,21 +640,24 @@ static const char PyXmlSec_KeysManagerLoadCert__doc__[] = \ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "filename", "format", "type", NULL}; + PyXmlSec_KeysManager* mgr = (PyXmlSec_KeysManager*)self; PyObject* filepath = NULL; unsigned int format = 0; unsigned int type = 0; + const char* filename; + int rv; + PYXMLSEC_DEBUGF("%p: load cert - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&II:load_cert", kwlist, PyString_FSConverter, &filepath, &format, &type)) { goto ON_FAIL; } - const char* filename = PyBytes_AsString(filepath); + filename = PyBytes_AsString(filepath); - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecCryptoAppKeysMngrCertLoad(((PyXmlSec_KeysManager*)self)->handle, filename, format, type); + rv = xmlSecCryptoAppKeysMngrCertLoad(mgr->handle, filename, format, type); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("cannot load cert"); @@ -665,20 +680,21 @@ static const char PyXmlSec_KeysManagerLoadCertFromMemory__doc__[] = \ static PyObject* PyXmlSec_KeysManagerLoadCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", "type", NULL}; + PyXmlSec_KeysManager* mgr = (PyXmlSec_KeysManager*)self; + const char* data = NULL; unsigned int type = 0; unsigned int format = 0; Py_ssize_t data_size = 0; + int rv; PYXMLSEC_DEBUGF("%p: load cert from memory - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s#II:load_cert", kwlist, &data, &data_size, &format, &type)) { goto ON_FAIL; } - xmlSecKeysMngrPtr handle = ((PyXmlSec_KeysManager*)self)->handle; - int rv; Py_BEGIN_ALLOW_THREADS; - rv = xmlSecCryptoAppKeysMngrCertLoadMemory(handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format, type); + rv = xmlSecCryptoAppKeysMngrCertLoadMemory(mgr->handle, (const xmlSecByte*)data, (xmlSecSize)data_size, format, type); Py_END_ALLOW_THREADS; if (rv < 0) { PyXmlSec_SetLastError("cannot load cert from memory"); @@ -750,9 +766,9 @@ static PyTypeObject _PyXmlSec_KeysManagerType = { 0, /* tp_descr_set */ 0, /* tp_dictoffset */ PyXmlSec_KeysManager__init__, /* tp_init */ - PyType_GenericAlloc, /* tp_alloc */ + 0, /* tp_alloc */ PyXmlSec_KeysManager__new__, /* tp_new */ - PyObject_Del /* tp_free */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_KeysManagerType = &_PyXmlSec_KeysManagerType; diff --git a/src/main.c b/src/main.c index c9121fa9..490a37e6 100644 --- a/src/main.c +++ b/src/main.c @@ -21,6 +21,9 @@ static int free_mode = _FREE_NONE; +#define MODULE_DOC "The tiny python wrapper around xmlsec1 (" XMLSEC_VERSION ") library" + + static void PyXmlSec_Free(int what) { PYXMLSEC_DEBUGF("free resources %d", what); switch (what) { @@ -160,7 +163,7 @@ static int PyXmlSec_PyClear(PyObject *self) { static PyModuleDef PyXmlSecModule = { PyModuleDef_HEAD_INIT, STRINGIFY(MODULE_NAME), /* name of module */ - STRINGIFY(MODULE_DOC), /* module documentation, may be NULL */ + MODULE_DOC, /* module documentation, may be NULL */ -1, /* size of per-interpreter state of the module, or -1 if the module keeps state in global variables. */ PyXmlSec_MainMethods, /* m_methods */ @@ -218,7 +221,7 @@ PYENTRY_FUNC_NAME(void) #ifdef PY3K module = PyModule_Create(&PyXmlSecModule); #else - module = Py_InitModule3(STRINGIFY(MODULE_NAME), PyXmlSec_MainMethods, STRINGIFY(MODULE_DOC)); + module = Py_InitModule3(STRINGIFY(MODULE_NAME), PyXmlSec_MainMethods, MODULE_DOC); #endif if (!module) { PY_MOD_RETURN(NULL); /* this really should never happen */ diff --git a/src/template.c b/src/template.c index d7bf5826..9a68dbd7 100644 --- a/src/template.c +++ b/src/template.c @@ -34,6 +34,7 @@ static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObjec PyXmlSec_Transform* sign = NULL; const char* id = NULL; const char* ns = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template create - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!O!|zzz:create", kwlist, @@ -42,7 +43,6 @@ static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObjec goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplSignatureCreateNsPref(node->_doc->_c_doc, c14n->id, sign->id, XSTR(id), XSTR(ns)); Py_END_ALLOW_THREADS; @@ -76,6 +76,7 @@ static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, P const char* id = NULL; const char* uri = NULL; const char* type = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_reference - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzz:add_reference", kwlist, @@ -83,7 +84,6 @@ static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, P { goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplSignatureAddReference(node->_c_node, digest->id, XSTR(id), XSTR(uri), XSTR(type)); Py_END_ALLOW_THREADS; @@ -110,6 +110,7 @@ static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, P PyXmlSec_LxmlElementPtr node = NULL; PyXmlSec_Transform* transform = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_transform - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!:add_transform", kwlist, @@ -117,7 +118,6 @@ static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, P { goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplReferenceAddTransform(node->_c_node, transform->id); Py_END_ALLOW_THREADS; @@ -144,13 +144,14 @@ static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, PyXmlSec_LxmlElementPtr node = NULL; const char* id = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template ensure_key_info - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:ensure_key_info", kwlist, PyXmlSec_LxmlElementConverter, &node, &id)) { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplSignatureEnsureKeyInfo(node->_c_node, XSTR(id)); Py_END_ALLOW_THREADS; @@ -177,6 +178,7 @@ static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyO PyXmlSec_LxmlElementPtr node = NULL; const char* name = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_key_name - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:add_key_name", kwlist, PyXmlSec_LxmlElementConverter, &node, &name)) @@ -184,7 +186,6 @@ static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyO goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplKeyInfoAddKeyName(node->_c_node, XSTR(name)); Py_END_ALLOW_THREADS; @@ -209,6 +210,7 @@ static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, Py static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_key_value - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:add_key_value", kwlist, PyXmlSec_LxmlElementConverter, &node)) @@ -216,7 +218,6 @@ static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, Py goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplKeyInfoAddKeyValue(node->_c_node); Py_END_ALLOW_THREADS; @@ -241,6 +242,7 @@ static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, Py static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_x509_data - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:add_x509_data", kwlist, PyXmlSec_LxmlElementConverter, &node)) @@ -248,7 +250,6 @@ static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, Py goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplKeyInfoAddX509Data(node->_c_node); Py_END_ALLOW_THREADS; @@ -273,6 +274,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyO static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_data_add_issuer_serial - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_issuer_serial", kwlist, @@ -280,7 +282,6 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyO { goto ON_FAIL; } - xmlNodePtr res; Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509DataAddIssuerSerial(node->_c_node); Py_END_ALLOW_THREADS; @@ -307,6 +308,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* PyXmlSec_LxmlElementPtr node = NULL; const char* name = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_issuer_serial_add_issuer_name - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:x509_issuer_serial_add_issuer_name", kwlist, @@ -314,7 +316,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509IssuerSerialAddIssuerName(node->_c_node, XSTR(name)); Py_END_ALLOW_THREADS; @@ -341,6 +343,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(P PyXmlSec_LxmlElementPtr node = NULL; const char* serial = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_issuer_serial_add_serial_number - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|z:x509_issuer_serial_add_serial_number", kwlist, @@ -348,7 +351,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(P { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509IssuerSerialAddSerialNumber(node->_c_node, XSTR(serial)); Py_END_ALLOW_THREADS; @@ -373,6 +376,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyOb static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_data_add_subject_name - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_subject_name", kwlist, @@ -380,7 +384,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyOb { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509DataAddSubjectName(node->_c_node); Py_END_ALLOW_THREADS; @@ -405,6 +409,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *ar static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_data_add_ski - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_ski", kwlist, @@ -412,7 +417,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *ar { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509DataAddSKI(node->_c_node); Py_END_ALLOW_THREADS; @@ -437,6 +442,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyOb static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_data_add_certificate - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_certificate", kwlist, @@ -444,7 +450,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyOb { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509DataAddCertificate(node->_c_node); Py_END_ALLOW_THREADS; @@ -469,6 +475,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *ar static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template x509_data_add_crl - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:x509_data_add_crl", kwlist, @@ -476,7 +483,7 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *ar { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplX509DataAddCRL(node->_c_node); Py_END_ALLOW_THREADS; @@ -509,6 +516,7 @@ static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args const char* id = NULL; const char* type = NULL; const char* recipient = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template add_encrypted_key - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzz:add_encrypted_key", kwlist, @@ -516,7 +524,7 @@ static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplKeyInfoAddEncryptedKey(node->_c_node, method->id, XSTR(id), XSTR(type), XSTR(recipient)); Py_END_ALLOW_THREADS; @@ -553,6 +561,7 @@ static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject * const char* mime_type = NULL; const char* encoding = NULL; const char* ns = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template encrypted_data_create - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O!|zzzzz:encrypted_data_create", kwlist, @@ -560,7 +569,7 @@ static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject * { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplEncDataCreate(node->_doc->_c_doc, method->id, XSTR(id), XSTR(type), XSTR(mime_type), XSTR(encoding)); Py_END_ALLOW_THREADS; @@ -592,6 +601,7 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyO PyXmlSec_LxmlElementPtr node = NULL; const char* id = NULL; const char* ns = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template encrypted_data_ensure_key_info - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&|zz:encrypted_data_ensure_key_info", kwlist, @@ -599,7 +609,7 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyO { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplEncDataEnsureKeyInfo(node->_c_node, XSTR(id)); Py_END_ALLOW_THREADS; @@ -627,6 +637,7 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, static char *kwlist[] = { "node", NULL}; PyXmlSec_LxmlElementPtr node = NULL; + xmlNodePtr res; PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&:encrypted_data_ensure_cipher_value", kwlist, @@ -634,7 +645,7 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplEncDataEnsureCipherValue(node->_c_node); Py_END_ALLOW_THREADS; @@ -660,6 +671,10 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, PyXmlSec_LxmlElementPtr node = NULL; PyObject* prefixes = NULL; + PyObject* sep; + int res; + const char* c_prefixes; + // transform_add_c14n_inclusive_namespaces PYXMLSEC_DEBUG("template encrypted_data_ensure_cipher_value - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O:transform_add_c14n_inclusive_namespaces", kwlist, @@ -669,7 +684,7 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, goto ON_FAIL; } if (PyList_Check(prefixes) || PyTuple_Check(prefixes)) { - PyObject* sep = PyString_FromString(" "); + sep = PyString_FromString(" "); prefixes = PyObject_CallMethod(sep, "join", "O", prefixes); Py_DECREF(sep); } else if (PyString_Check(prefixes)) { @@ -683,8 +698,8 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, goto ON_FAIL; } - int res; - const char* c_prefixes = PyString_AsString(prefixes); + + c_prefixes = PyString_AsString(prefixes); Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplTransformAddC14NInclNamespaces(node->_c_node, XSTR(c_prefixes)); Py_END_ALLOW_THREADS; diff --git a/src/tree.c b/src/tree.c index 3d17b329..ac23b53f 100644 --- a/src/tree.c +++ b/src/tree.c @@ -27,6 +27,7 @@ static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject PyXmlSec_LxmlElementPtr node = NULL; const char* name = NULL; const char* ns = (const char*)xmlSecDSigNs; + xmlNodePtr res; PYXMLSEC_DEBUG("tree find_child - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_child", kwlist, @@ -34,7 +35,7 @@ static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecFindChild(node->_c_node, XSTR(name), XSTR(ns)); Py_END_ALLOW_THREADS; @@ -62,6 +63,7 @@ static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObjec PyXmlSec_LxmlElementPtr node = NULL; const char* name = NULL; const char* ns = (const char*)xmlSecDSigNs; + xmlNodePtr res; PYXMLSEC_DEBUG("tree find_parent - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_parent", kwlist, @@ -69,7 +71,7 @@ static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObjec { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecFindParent(node->_c_node, XSTR(name), XSTR(ns)); Py_END_ALLOW_THREADS; @@ -97,6 +99,7 @@ static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject PyXmlSec_LxmlElementPtr node = NULL; const char* name = NULL; const char* ns = (const char*)xmlSecDSigNs; + xmlNodePtr res; PYXMLSEC_DEBUG("tree find_node - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&s|s:find_node", kwlist, @@ -104,7 +107,7 @@ static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject { goto ON_FAIL; } - xmlNodePtr res; + Py_BEGIN_ALLOW_THREADS; res = xmlSecFindNode(node->_c_node, XSTR(name), XSTR(ns)); Py_END_ALLOW_THREADS; @@ -136,12 +139,17 @@ static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *k const xmlChar** list = NULL; + Py_ssize_t n; + PyObject* tmp; + PyObject* key; + Py_ssize_t i; + PYXMLSEC_DEBUG("tree add_ids - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&O:add_ids", kwlist, PyXmlSec_LxmlElementConverter, &node, &ids)) { goto ON_FAIL; } - Py_ssize_t n = PyObject_Length(ids); + n = PyObject_Length(ids); if (n < 0) goto ON_FAIL; list = (const xmlChar**)xmlMalloc(sizeof(xmlChar*) * (n + 1)); @@ -150,9 +158,7 @@ static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *k goto ON_FAIL; } - PyObject* tmp; - PyObject* key; - for (Py_ssize_t i = 0; i < n; ++i) { + for (i = 0; i < n; ++i) { key = PyLong_FromSsize_t(i); if (key == NULL) goto ON_FAIL; tmp = PyObject_GetItem(ids, key); diff --git a/src/utils.c b/src/utils.c index 679a1b2d..ea6867f3 100644 --- a/src/utils.c +++ b/src/utils.c @@ -10,10 +10,14 @@ #include "utils.h" PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { + PyObject* data; + PyObject* utf8; + PyObject* tmp = NULL; + if (PyObject_HasAttrString(file, "read")) { - PyObject* data = PyObject_CallMethod(file, "read", NULL); + data = PyObject_CallMethod(file, "read", NULL); if (data != NULL && PyUnicode_Check(data)) { - PyObject* utf8 = PyUnicode_AsUTF8String(data); + utf8 = PyUnicode_AsUTF8String(data); Py_DECREF(data); data = utf8; } @@ -21,7 +25,6 @@ PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { return data; } *is_content = 0; - PyObject* tmp = NULL; if (!PyString_FSConverter(file, &tmp)) { return NULL; } @@ -30,20 +33,24 @@ PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value) { PyObject* tmp = PyString_FromString(value); + int r; + if (tmp == NULL) { return -1; } - int r = PyObject_SetAttrString(obj, name, tmp); + r = PyObject_SetAttrString(obj, name, tmp); Py_DECREF(tmp); return r; } int PyXmlSec_SetLongAttr(PyObject* obj, const char* name, long value) { PyObject* tmp = PyLong_FromLong(value); + int r; + if (tmp == NULL) { return -1; } - int r = PyObject_SetAttrString(obj, name, tmp); + r = PyObject_SetAttrString(obj, name, tmp); Py_DECREF(tmp); return r; } From 4d44b935e3a28c35989fbea1d084b58cb543eea8 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 10 Aug 2017 01:29:05 +0300 Subject: [PATCH 062/378] add windows support --- .travis.yml | 2 +- MANIFEST.in | 4 +- README.rst | 76 +++++++----- doc/source/install.rst | 25 ++++ extra.py | 101 ++++++++++++++++ setup.py | 101 ++++------------ setupinfo.py | 256 +++++++++++++++++++++++++++++++++++++++++ tests/base.py | 27 ++++- version.txt | 1 + 9 files changed, 480 insertions(+), 113 deletions(-) create mode 100644 extra.py create mode 100644 setupinfo.py create mode 100644 version.txt diff --git a/.travis.yml b/.travis.yml index ba838201..47af0630 100644 --- a/.travis.yml +++ b/.travis.yml @@ -18,7 +18,7 @@ addons: - libxslt1-dev - pkg-config before_install: -- sed -i "s/1.0.1/${TRAVIS_TAG:-1.0.1}/" setup.py +- echo "${TRAVIS_TAG:-1.0.1.dev}" >version.txt install: - travis_retry pip install -r requirements-test.txt - travis_retry pip install -e "." diff --git a/MANIFEST.in b/MANIFEST.in index 07ed1203..0b0468dc 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,4 +1,6 @@ include src/* include requirements*.txt include LICENSE - +include version.txt +include setupinfo.py +include extra.py diff --git a/README.rst b/README.rst index a1ca111a..4f9c09ff 100644 --- a/README.rst +++ b/README.rst @@ -80,27 +80,52 @@ Mac If you get any fatal errors about missing .h files, update your C_INCLUDE_PATH environment variable to include the appropriate files from the libxml2 and libxmlsec1 libraries. + +Windows (Wheel) +^^^^^^^^^^^^^^^ + +#. Download appropriate binary wheel from `ci.appveyor.com `_ (see build`s artifacts). + +#. Install wheel + + .. code-block:: bash + + pip install + + +Windows (pip) +^^^^^^^^^^^^^ + +#. Configure build environment, see `wiki.python.org `_ for more details. + +#. Install from pip + + .. code-block:: bash + + pip install xmlsec + + Manual ------ -1. Clone the **xmlsec** repository to your local computer. +#. Clone the **xmlsec** repository to your local computer. -.. code-block:: bash + .. code-block:: bash - git clone git://github.com/mehcode/python-xmlsec.git + git clone git://github.com/mehcode/python-xmlsec.git -2. Change into the **xmlsec** root directory. +#. Change into the **xmlsec** root directory. -.. code-block:: bash + .. code-block:: bash - cd /path/to/xmlsec + cd /path/to/xmlsec -3. Install the project and all its dependencies using `pip`. +#. Install the project and all its dependencies using `pip`. -.. code-block:: bash + .. code-block:: bash - pip install . + pip install . ************ @@ -110,44 +135,43 @@ Contributing Setting up your environment --------------------------- -1. Follow steps 1 and 2 of the [manual installation instructions][]. +#. Follow steps 1 and 2 of the `manual installation instructions <#manual>`_. -[manual installation instructions]: #manual -2. Initialize a virtual environment to develop in. +#. Initialize a virtual environment to develop in. This is done so as to ensure every contributor is working with close-to-identicial versions of packages. -.. code-block:: bash + .. code-block:: bash - mkvirtualenv xmlsec + mkvirtualenv xmlsec - The `mkvirtualenv` command is available from `virtualenvwrapper` which - can be installed by following: http://virtualenvwrapper.readthedocs.org/en/latest/install.html#basic-installation + The `mkvirtualenv` command is available from `virtualenvwrapper` which + can be installed by following `link `_ -3. Install **xmlsec** in development mode with testing enabled. +#. Install **xmlsec** in development mode with testing enabled. This will download all dependencies required for running the unit tests. -.. code-block:: bash + .. code-block:: bash - pip install -r requirements-test.txt - pip install -e "." + pip install -r requirements-test.txt + pip install -e "." Running the test suite ---------------------- -1. [Set up your environment](#setting-up-your-environment). +#. [Set up your environment](#setting-up-your-environment). -2. Run the unit tests. +#. Run the unit tests. -.. code-block:: bash + .. code-block:: bash - py.test tests + py.test tests -3. Tests configuration -Env variable **PYXMLSEC_TEST_ITERATIONS** specifies number of test iterations to detect memory leaks. +#. Tests configuration + Env variable **PYXMLSEC_TEST_ITERATIONS** specifies number of test iterations to detect memory leaks. Reporting a issue ----------------- diff --git a/doc/source/install.rst b/doc/source/install.rst index 43987710..a60d4cff 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -40,3 +40,28 @@ Mac brew install libxml2 libxmlsec1 pip install xmlsec + + +Windows (Wheel) +^^^^^^^^^^^^^^^ + +#. Download appropriate binary wheels from `appveyor `_ (see build`s artifacts). + +#. Install downloaded wheel + + .. code-block:: bash + + pip install + + +Windows (pip) +^^^^^^^^^^^^^ + +#. Configure build environment, see `wiki.python.org `_ for more details. + +#. Install from pip + + .. code-block:: bash + + pip install xmlsec + diff --git a/extra.py b/extra.py new file mode 100644 index 00000000..fe9c899d --- /dev/null +++ b/extra.py @@ -0,0 +1,101 @@ +import os +import sys + +try: + from urlparse import urljoin + from urllib import urlretrieve, urlcleanup +except ImportError: + from urllib.parse import urljoin + from urllib.request import urlretrieve, urlcleanup + + +# use pre-built libraries on Windows +def get_prebuilt_libs(download_dir, static_include_dirs, static_library_dirs): + assert sys.platform.startswith('win') + libs = download_and_extract_windows_binaries(download_dir) + for ln, path in libs.items(): + if ln == 'xmlsec1': + i = os.path.join(path, 'include', 'xmlsec1') + else: + i = os.path.join(path, 'include') + + l = os.path.join(path, 'lib') + assert os.path.exists(i), 'does not exist: %s' % i + assert os.path.exists(l), 'does not exist: %s' % l + static_include_dirs.append(i) + static_library_dirs.append(l) + + +def download_and_extract_windows_binaries(destdir): + if sys.version_info < (3, 5): + if sys.maxsize > 2147483647: + url = "https://ci.appveyor.com/api/buildjobs/7q4nvmkdnu05dul6/artifacts/" + suffix = "vs2008.win64" + else: + url = "https://ci.appveyor.com/api/buildjobs/tdpx6rprr5431ec9/artifacts/" + suffix = "vs2008.win32" + else: + if sys.maxsize > 2147483647: + url = "https://ci.appveyor.com/api/buildjobs/hij3a6776pdv2007/artifacts/" + suffix = "win64" + else: + url = "https://ci.appveyor.com/api/buildjobs/7k878q7rvogcdyd9/artifacts/" + suffix = "win32" + + libs = { + 'libxml2': 'libxml2-2.9.4.{}.zip'.format(suffix), + 'libxslt': 'libxslt-1.1.29.{}.zip'.format(suffix), + 'zlib': 'zlib-1.2.8.{}.zip'.format(suffix), + 'iconv': 'iconv-1.14.{}.zip'.format(suffix), + 'openssl': 'openssl-1.0.1.{}.zip'.format(suffix), + 'xmlsec': 'xmlsec-1.2.24.{}.zip'.format(suffix), + } + + if not os.path.exists(destdir): + os.makedirs(destdir) + + for ln, fn in libs.items(): + srcfile = urljoin(url, fn) + destfile = os.path.join(destdir, fn) + if os.path.exists(destfile + ".keep"): + print('Using local copy of "{}"'.format(srcfile)) + else: + print('Retrieving "%s" to "%s"' % (srcfile, destfile)) + urlcleanup() # work around FTP bug 27973 in Py2.7.12+ + urlretrieve(srcfile, destfile) + + libs[ln] = unpack_zipfile(destfile, destdir) + + return libs + + +def find_top_dir_of_zipfile(zipfile): + topdir = None + files = [f.filename for f in zipfile.filelist] + dirs = [d for d in files if d.endswith('/')] + if dirs: + dirs.sort(key=len) + topdir = dirs[0] + topdir = topdir[:topdir.index("/")+1] + for path in files: + if not path.startswith(topdir): + topdir = None + break + assert topdir, ( + "cannot determine single top-level directory in zip file %s" % + zipfile.filename) + return topdir.rstrip('/') + + +def unpack_zipfile(zipfn, destdir): + assert zipfn.endswith('.zip') + import zipfile + print('Unpacking %s into %s' % (os.path.basename(zipfn), destdir)) + f = zipfile.ZipFile(zipfn) + try: + extracted_dir = os.path.join(destdir, find_top_dir_of_zipfile(f)) + f.extractall(path=destdir) + finally: + f.close() + assert os.path.exists(extracted_dir), 'missing: %s' % extracted_dir + return extracted_dir diff --git a/setup.py b/setup.py index 65ff5e6b..191499cd 100644 --- a/setup.py +++ b/setup.py @@ -1,110 +1,52 @@ -from __future__ import print_function - -import glob -import os from setuptools import setup from setuptools import Extension from setuptools.command import build_ext - -__name__ = "xmlsec" -__version__ = "1.0.1" -__description__ = "Python bindings for the XML Security Library" - - -def is_debug(): - return bool(os.getenv("PYXMLSEC_DEBUG")) - - -macroses = [("MODULE_NAME", __name__), ("MODULE_VERSION", __version__), ("MODULE_DOC", __description__)] -cflags = ["-g", "-std=c99", "-fno-strict-aliasing", "-Wno-error=declaration-after-statement", "-Werror=implicit-function-declaration"] - - -if is_debug(): - macroses.append(("PYXMLSEC_ENABLE_DEBUG", "1")) - cflags.extend(["-Wall", "-O0"]) -else: - cflags.extend(["-Os"]) - - -def add_to_list(target, up, need_to_escape=None): - if up is None: - return target - - value = set(target) - if need_to_escape: - for x in up: - if x[0] in need_to_escape: - value.add((x[0], '"{0}"'.format(x[1]))) - else: - value.add(x) - else: - value.update(up) - target[:] = list(value) - - -def find_sources(path): - return glob.glob(os.path.join(path, "*.c")) - - -def parse_requirements(filename, __cache={}): - try: - return __cache[filename] - except KeyError: - with open(filename) as stream: - result = __cache[filename] = [x for x in (y.strip() for y in stream) if x and not x.startswith('#')] - return result +import setupinfo class BuildExt(build_ext.build_ext): def run(self): - self.patch_xmlsec() - build_ext.build_ext.run(self) - - def patch_xmlsec(self): # at this moment all setup_requires are installed and we can safety import them - pkgconfig = __import__("pkgconfig") - lxml = __import__("lxml") - - ext = self.ext_map[__name__] - config = pkgconfig.parse("xmlsec1") - # need to escape XMLSEC_CRYPTO - # added build flags from pkg-config - for item in ('libraries', 'library_dirs', 'include_dirs'): - add_to_list(getattr(ext, item), config.get(item)) + self.patch_options() + build_ext.build_ext.run(self) - add_to_list(ext.define_macros, config.get('define_macros'), {"XMLSEC_CRYPTO"}) - add_to_list(ext.include_dirs, lxml.get_include()) + def patch_options(self): + ext = self.ext_map[setupinfo.name()] + ext.define_macros.extend(setupinfo.define_macros()) + ext.include_dirs.extend(setupinfo.include_dirs()) + ext.libraries.extend(setupinfo.libraries()) + ext.library_dirs.extend(setupinfo.library_dirs()) _xmlsec = Extension( - __name__, - sources=find_sources("./src"), - extra_compile_args=cflags, + setupinfo.name(), + sources=setupinfo.sources(), + extra_compile_args=setupinfo.cflags(), libraries=[], library_dirs=[], include_dirs=[], - define_macros=macroses + define_macros=[], ) setup( - name=__name__, - version=__version__, - description=__description__, + name=setupinfo.name(), + version=setupinfo.version(), + description=setupinfo.description(), ext_modules=[_xmlsec], cmdclass={'build_ext': BuildExt}, - setup_requires=parse_requirements('requirements.txt'), - install_requires=parse_requirements('requirements.txt'), + setup_requires=setupinfo.requirements(), + install_requires=setupinfo.requirements(), author="Bulat Gaifullin", author_email='support@mehcode.com', maintainer='Bulat Gaifullin', maintainer_email='gaifullinbf@gmail.com', url='https://github.com/mehcode/python-xmlsec', - download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % __version__, + download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % setupinfo.version(), license='MIT', keywords=["xmlsec"], classifiers=[ - 'Development Status :: 4 - Beta', + setupinfo.dev_status(), 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', @@ -112,8 +54,9 @@ def patch_xmlsec(self): 'Programming Language :: C', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.3', 'Programming Language :: Python :: 3.4', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', 'Topic :: Text Processing :: Markup :: XML' ], ) diff --git a/setupinfo.py b/setupinfo.py new file mode 100644 index 00000000..c126fb52 --- /dev/null +++ b/setupinfo.py @@ -0,0 +1,256 @@ +from __future__ import print_function + +import glob +import os +import pkg_resources +import sys + +from distutils.errors import DistutilsOptionError + + +WIN32 = sys.platform.lower().startswith('win') + +__MODULE_NAME = "xmlsec" +__MODULE_VERSION = None +__MODULE_DESCRIPTION = "Python bindings for the XML Security Library" +__MODULE_REQUIREMENTS = None +__XMLSEC_CONFIG = None + + +def name(): + return __MODULE_NAME + + +def version(): + global __MODULE_VERSION + if __MODULE_VERSION is None: + with open(os.path.join(get_base_dir(), 'version.txt')) as f: + __MODULE_VERSION = f.read().strip() + return __MODULE_VERSION + + +def description(): + return __MODULE_DESCRIPTION + + +def sources(): + return glob.glob(os.path.join(get_base_dir(), "src", "*.c")) + + +def define_macros(): + macros = [ + ("MODULE_NAME", __MODULE_NAME), + ("MODULE_VERSION", version()), + ] + if OPTION_ENABLE_DEBUG: + macros.append(("PYXMLSEC_ENABLE_DEBUG", "1")) + + macros.extend(xmlsec_config()['define_macros']) + + return macros + + +def cflags(): + options = [] + if WIN32: + options.append("/Zi") + else: + options.append("-g") + options.append("-std=c99") + options.append("-fno-strict-aliasing") + options.append("-Wno-error=declaration-after-statement") + options.append("-Werror=implicit-function-declaration") + + if OPTION_ENABLE_DEBUG: + options.append("-Wall") + options.append("-O0") + else: + options.append("-Os") + + return options + + +def include_dirs(): + import lxml + + dirs = xmlsec_config()['include_dirs'] + dirs.extend(lxml.get_include()) + return dirs + + +def libraries(): + return xmlsec_config()['libraries'] + + +def library_dirs(): + return xmlsec_config()['library_dirs'] + + +def dev_status(): + _version = version() + if 'a' in _version: + return 'Development Status :: 3 - Alpha' + elif 'b' in _version or 'c' in _version: + return 'Development Status :: 4 - Beta' + else: + return 'Development Status :: 5 - Production/Stable' + + +def requirements(): + global __MODULE_REQUIREMENTS + if __MODULE_REQUIREMENTS is None: + with open(os.path.join(get_base_dir(), "requirements.txt")) as f: + __MODULE_REQUIREMENTS = [str(req) for req in pkg_resources.parse_requirements(f)] + return __MODULE_REQUIREMENTS + + +def xmlsec_config(): + global __XMLSEC_CONFIG + + if __XMLSEC_CONFIG is None: + __XMLSEC_CONFIG = load_xmlsec1_config() + + return __XMLSEC_CONFIG + + +def load_xmlsec1_config(): + config = None + + if WIN32: + import extra + + config = { + 'define_macros': [ + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('__XMLSEC_FUNCTION__', '__FUNCTION__'), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', '1'), + ('XMLSEC_STATIC', '1'), + ('inline', '__inline'), + ], + 'libraries': [ + 'libxmlsec_a', + 'libxmlsec-openssl_a', + 'libeay32', + 'iconv_a', + 'libxslt_a', + 'libexslt_a', + 'libxml2_a', + 'zlib', + 'WS2_32', + 'Advapi32', + 'User32', + 'Gdi32', + 'Crypt32', + ], + 'include_dirs': [], + 'library_dirs': [], + } + + extra.get_prebuilt_libs( + OPTION_DOWNLOAD_DIR, config['include_dirs'], config['library_dirs'] + ) + else: + import pkgconfig + + try: + config = pkgconfig.parse('xmlsec1') + except EnvironmentError: + pass + + if config is None or not config.get('libraries'): + fatal_xmlsec1_error() + + config.setdefault('libraries', []) + config.setdefault('include_dirs', []) + config.setdefault('library_dirs', []) + # fix macros + macros = config.setdefault('define_macros', []) + for i, v in enumerate(macros): + if v[0] == 'XMLSEC_CRYPTO': + macros[i] = ('XMLSEC_CRYPTO', '"{0}"'.format(v[1])) + break + return config + + +def fatal_xmlsec1_error(): + print('*********************************************************************************') + print('Could not find xmlsec1 config. Are libxmlsec1-dev and pkg-config installed?') + if sys.platform in ('darwin',): + print('Perhaps try: xcode-select --install') + print('*********************************************************************************') + sys.exit(1) + + +def get_base_dir(): + return os.path.abspath(os.path.dirname(sys.argv[0])) + + +if sys.version_info[0] >= 3: + _system_encoding = sys.getdefaultencoding() + if _system_encoding is None: + _system_encoding = "iso-8859-1" + + def decode_input(data): + if isinstance(data, str): + return data + return data.decode(_system_encoding) +else: + def decode_input(data): + return data + + +def env_var(n): + value = os.getenv(n) + if value: + value = decode_input(value) + if sys.platform == 'win32' and ';' in value: + return value.split(';') + else: + return value.split() + else: + return [] + + +def env_var_name(n): + return "PYXMLSEC_" + n.upper().replace('-', '_') + + +# Option handling: + +def has_option(n): + try: + sys.argv.remove('--%s' % n) + return True + except ValueError: + pass + # allow passing all cmd line options also as environment variables + env_val = os.getenv(env_var_name(n), 'false').lower() + return env_val in ("true", "1") + + +def option_value(n, default=None): + for index, option in enumerate(sys.argv): + if option == '--' + n: + if index+1 >= len(sys.argv): + raise DistutilsOptionError( + 'The option %s requires a value' % option) + value = sys.argv[index+1] + sys.argv[index:index+2] = [] + return value + if option.startswith('--' + n + '='): + value = option[len(n)+3:] + sys.argv[index:index+1] = [] + return value + return os.getenv(env_var_name(n), default) + + +OPTION_ENABLE_DEBUG = has_option('enable-debug') +OPTION_DOWNLOAD_DIR = option_value('download-dir', 'build/extra') diff --git a/tests/base.py b/tests/base.py index abbe6058..b05de1de 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,6 +1,5 @@ import gc import os -import resource import sys from lxml import etree @@ -8,14 +7,30 @@ import unittest + etype = type(etree.Element("test")) ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs} -def safe_int(s): +try: + import resource + + def get_memory_usage(): + return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss +except ImportError: + resource = None + + def get_memory_usage(): + return 0 + + +def get_iterations(): + if sys.platform in ('win32',): + return 0 + try: - return int(s) + return int(os.getenv("PYXMLSEC_TEST_ITERATIONS", "10")) except ValueError: return 0 @@ -23,7 +38,7 @@ def safe_int(s): class TestMemoryLeaks(unittest.TestCase): maxDiff = None - iterations = safe_int(os.getenv("PYXMLSEC_TEST_ITERATIONS", "10")) + iterations = get_iterations() data_dir = os.path.join(os.path.dirname(__file__), "data") @@ -104,8 +119,8 @@ def assertXmlEqual(self, first, second, msg=None): self.fail('text: %r != %r. %s' % (first.text, second.text, msg)) if not xml_text_compare(first.tail, second.tail): self.fail('tail: %r != %r. %s' % (first.tail, second.tail, msg)) - cl1 = first.getchildren() - cl2 = second.getchildren() + cl1 = sorted(first.getchildren(), key=lambda x: x.tag) + cl2 = sorted(second.getchildren(), key=lambda x: x.tag) if len(cl1) != len(cl2): self.fail('children length differs, %i != %i. %s' % (len(cl1), len(cl2), msg)) i = 0 diff --git a/version.txt b/version.txt new file mode 100644 index 00000000..e7526496 --- /dev/null +++ b/version.txt @@ -0,0 +1 @@ +1.0.1.dev0 From bed23d0ffff4ce55be054ea35efd7457244e7cd8 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Thu, 10 Aug 2017 01:29:58 +0300 Subject: [PATCH 063/378] add appveyor --- .appveyor.yml | 34 ++++++++++++++++++++++++++++++++++ .gitignore | 1 + README.rst | 2 ++ 3 files changed, 37 insertions(+) create mode 100644 .appveyor.yml diff --git a/.appveyor.yml b/.appveyor.yml new file mode 100644 index 00000000..0a306dec --- /dev/null +++ b/.appveyor.yml @@ -0,0 +1,34 @@ +version: 1.3.{build} + +environment: + matrix: + - python: 27 + - python: 27-x64 + - python: 35 + - python: 35-x64 + - python: 36 + - python: 36-x64 + +install: + - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% + - python -m pip.__main__ install -U pip wheel setuptools + - pip install -r requirements-test.txt + +build: off +build_script: + # configure version + - ps: >- + If ($env:APPVEYOR_REPO_TAG -Eq "true" ) { + $version = "$env:APPVEYOR_REPO_TAG_NAME" + } Else { + $version = "$env:APPVEYOR_BUILD_VERSION.dev0" + } + $version | Set-Content version.txt + - python setup.py build bdist_wheel + - ps: Get-ChildItem dist\*.whl | % { pip install $_.FullName } + +test: off +test_script: + - pip list + - py.test -v tests + - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } diff --git a/.gitignore b/.gitignore index f39e8aba..be6e8c15 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ .* !.editorconfig !.travis* +!.appveyor* !.git* # Python diff --git a/README.rst b/README.rst index 4f9c09ff..ffd73c17 100644 --- a/README.rst +++ b/README.rst @@ -3,6 +3,8 @@ python-xmlsec .. image:: https://travis-ci.org/mehcode/python-xmlsec.png?branch=master :target: https://travis-ci.org/mehcode/python-xmlsec +.. image:: https://ci.appveyor.com/api/projects/status/20rtt2wv96gag9cy?svg=true + :target: https://ci.appveyor.com/project/bgaifullin/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg :target: https://pypi.python.org/pypi/xmlsec .. image:: https://img.shields.io/badge/docs-latest-green.svg From 7f347cf3a0b1b34f88902108bf260521af1fcedc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Sindri=20Gu=C3=B0mundsson?= Date: Tue, 15 Aug 2017 13:14:05 +0000 Subject: [PATCH 064/378] Fix name collision with lxml's setupinfo.py When installing (ubuntu and arch, python 3.6.2 and python 3.5.x), lxml installation fails because it tries to import its own `setupinfo.py`, but gets python-xmlsec's `setupinfo.py`. Rename the module to make sure we don't get another name collision. --- setup.py | 32 ++++++++++++++--------------- setupinfo.py => xmlsec_setupinfo.py | 0 2 files changed, 16 insertions(+), 16 deletions(-) rename setupinfo.py => xmlsec_setupinfo.py (100%) diff --git a/setup.py b/setup.py index 191499cd..3fff1b17 100644 --- a/setup.py +++ b/setup.py @@ -2,7 +2,7 @@ from setuptools import Extension from setuptools.command import build_ext -import setupinfo +import xmlsec_setupinfo class BuildExt(build_ext.build_ext): @@ -12,17 +12,17 @@ def run(self): build_ext.build_ext.run(self) def patch_options(self): - ext = self.ext_map[setupinfo.name()] - ext.define_macros.extend(setupinfo.define_macros()) - ext.include_dirs.extend(setupinfo.include_dirs()) - ext.libraries.extend(setupinfo.libraries()) - ext.library_dirs.extend(setupinfo.library_dirs()) + ext = self.ext_map[xmlsec_setupinfo.name()] + ext.define_macros.extend(xmlsec_setupinfo.define_macros()) + ext.include_dirs.extend(xmlsec_setupinfo.include_dirs()) + ext.libraries.extend(xmlsec_setupinfo.libraries()) + ext.library_dirs.extend(xmlsec_setupinfo.library_dirs()) _xmlsec = Extension( - setupinfo.name(), - sources=setupinfo.sources(), - extra_compile_args=setupinfo.cflags(), + xmlsec_setupinfo.name(), + sources=xmlsec_setupinfo.sources(), + extra_compile_args=xmlsec_setupinfo.cflags(), libraries=[], library_dirs=[], include_dirs=[], @@ -30,23 +30,23 @@ def patch_options(self): ) setup( - name=setupinfo.name(), - version=setupinfo.version(), - description=setupinfo.description(), + name=xmlsec_setupinfo.name(), + version=xmlsec_setupinfo.version(), + description=xmlsec_setupinfo.description(), ext_modules=[_xmlsec], cmdclass={'build_ext': BuildExt}, - setup_requires=setupinfo.requirements(), - install_requires=setupinfo.requirements(), + setup_requires=xmlsec_setupinfo.requirements(), + install_requires=xmlsec_setupinfo.requirements(), author="Bulat Gaifullin", author_email='support@mehcode.com', maintainer='Bulat Gaifullin', maintainer_email='gaifullinbf@gmail.com', url='https://github.com/mehcode/python-xmlsec', - download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % setupinfo.version(), + download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % xmlsec_setupinfo.version(), license='MIT', keywords=["xmlsec"], classifiers=[ - setupinfo.dev_status(), + xmlsec_setupinfo.dev_status(), 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', diff --git a/setupinfo.py b/xmlsec_setupinfo.py similarity index 100% rename from setupinfo.py rename to xmlsec_setupinfo.py From 15e6ce62658cc707dbdce94a13b6bfce8352a7ac Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 15 Aug 2017 17:02:35 +0300 Subject: [PATCH 065/378] Fix installation via pip --- MANIFEST.in | 4 ++-- extra.py => xmlsec_extra.py | 0 xmlsec_setupinfo.py | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) rename extra.py => xmlsec_extra.py (100%) diff --git a/MANIFEST.in b/MANIFEST.in index 0b0468dc..9cafd112 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -2,5 +2,5 @@ include src/* include requirements*.txt include LICENSE include version.txt -include setupinfo.py -include extra.py +include xmlsec_setupinfo.py +include xmlsec_extra.py diff --git a/extra.py b/xmlsec_extra.py similarity index 100% rename from extra.py rename to xmlsec_extra.py diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py index c126fb52..8815808b 100644 --- a/xmlsec_setupinfo.py +++ b/xmlsec_setupinfo.py @@ -117,7 +117,7 @@ def load_xmlsec1_config(): config = None if WIN32: - import extra + import xmlsec_extra config = { 'define_macros': [ @@ -154,7 +154,7 @@ def load_xmlsec1_config(): 'library_dirs': [], } - extra.get_prebuilt_libs( + xmlsec_extra.get_prebuilt_libs( OPTION_DOWNLOAD_DIR, config['include_dirs'], config['library_dirs'] ) else: From ba8eacbf73e6f4c432bd4e96542dfa6698e46b1e Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Sun, 4 Feb 2018 00:14:24 +0300 Subject: [PATCH 066/378] fixed build with python3.4 on centos 7 --- xmlsec_setupinfo.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py index 8815808b..b4b5a817 100644 --- a/xmlsec_setupinfo.py +++ b/xmlsec_setupinfo.py @@ -171,12 +171,13 @@ def load_xmlsec1_config(): config.setdefault('libraries', []) config.setdefault('include_dirs', []) config.setdefault('library_dirs', []) - # fix macros - macros = config.setdefault('define_macros', []) + # fix macros, ensure that macros is list + macros = list(config.get('define_macros', [])) for i, v in enumerate(macros): if v[0] == 'XMLSEC_CRYPTO': macros[i] = ('XMLSEC_CRYPTO', '"{0}"'.format(v[1])) break + config['define_macros'] = macros return config From 2de15984ee7590bb0a1b5a17f9e1b7b509d0bee4 Mon Sep 17 00:00:00 2001 From: Jaye Doepke Date: Tue, 6 Feb 2018 11:23:50 -0600 Subject: [PATCH 067/378] Fix build on CentOS 6 w/ xmlsec1-1.2.19-3 pkgconfig doesn't parse the XMLSEC_CRYPTO macro value correctly from xmlsec1-1.2.19-3 on CentOS 6 (the Changelog for [that RPM](https://centos.pkgs.org/6/centos-x86_64/xmlsec1-1.2.20-4.el6.x86_64.rpm.html) suggests there's been some bugs). ``` 2014-05-28 - Simo Sorce - 1.2.20-2 - Update pkg-config fix patch to apply w/o fuzz ... 2014-05-23 - Simo Sorce - 1.2.19-6 - Fix incomplete patch 2014-05-23 - Simo Sorce - 1.2.19-5 - Add patch to deal with different behavior of pkg-config in RHEL6 ``` This change fixes the build for xmlsec1-1.2.19-3. --- xmlsec_setupinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py index b4b5a817..829b4665 100644 --- a/xmlsec_setupinfo.py +++ b/xmlsec_setupinfo.py @@ -174,7 +174,7 @@ def load_xmlsec1_config(): # fix macros, ensure that macros is list macros = list(config.get('define_macros', [])) for i, v in enumerate(macros): - if v[0] == 'XMLSEC_CRYPTO': + if v[0] == 'XMLSEC_CRYPTO' and not (v[1].startswith('"') and v[1].endswith('"')): macros[i] = ('XMLSEC_CRYPTO', '"{0}"'.format(v[1])) break config['define_macros'] = macros From b78b21b169cd1df4f314689b5bcd2d8db0571ba4 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 31 Aug 2018 22:16:22 +0300 Subject: [PATCH 068/378] Ensure xml_config options are list --- xmlsec_setupinfo.py | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py index 829b4665..69bd2a3a 100644 --- a/xmlsec_setupinfo.py +++ b/xmlsec_setupinfo.py @@ -168,9 +168,10 @@ def load_xmlsec1_config(): if config is None or not config.get('libraries'): fatal_xmlsec1_error() - config.setdefault('libraries', []) - config.setdefault('include_dirs', []) - config.setdefault('library_dirs', []) + # make sure that all options are list + for x in ('libraries', 'include_dirs', 'library_dirs'): + config[x] = list(config.get(x) or []) + # fix macros, ensure that macros is list macros = list(config.get('define_macros', [])) for i, v in enumerate(macros): From 43fe1ff7a1e36f9dd36f48a7f7da39fc4b5a451c Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Fri, 31 Aug 2018 22:28:50 +0300 Subject: [PATCH 069/378] Download windows binaries from github --- xmlsec_extra.py | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/xmlsec_extra.py b/xmlsec_extra.py index fe9c899d..9bf6c86a 100644 --- a/xmlsec_extra.py +++ b/xmlsec_extra.py @@ -27,19 +27,16 @@ def get_prebuilt_libs(download_dir, static_include_dirs, static_library_dirs): def download_and_extract_windows_binaries(destdir): + url = "https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/" if sys.version_info < (3, 5): if sys.maxsize > 2147483647: - url = "https://ci.appveyor.com/api/buildjobs/7q4nvmkdnu05dul6/artifacts/" suffix = "vs2008.win64" else: - url = "https://ci.appveyor.com/api/buildjobs/tdpx6rprr5431ec9/artifacts/" suffix = "vs2008.win32" else: if sys.maxsize > 2147483647: - url = "https://ci.appveyor.com/api/buildjobs/hij3a6776pdv2007/artifacts/" suffix = "win64" else: - url = "https://ci.appveyor.com/api/buildjobs/7k878q7rvogcdyd9/artifacts/" suffix = "win32" libs = { From eae4c8b2b479ed0bae09434288b2448865dac5f1 Mon Sep 17 00:00:00 2001 From: Andy Freeland Date: Fri, 19 Oct 2018 23:26:53 -0700 Subject: [PATCH 070/378] Python 3.7 This patch adds Python 3.7 testing to Travis/AppVeyor. --- .appveyor.yml | 2 ++ .travis.yml | 14 ++++++++++---- README.rst | 1 + setup.py | 1 + 4 files changed, 14 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 0a306dec..a9a7cde2 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -8,6 +8,8 @@ environment: - python: 35-x64 - python: 36 - python: 36-x64 + - python: 37 + - python: 37-x64 install: - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% diff --git a/.travis.yml b/.travis.yml index 47af0630..381da47f 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,10 +4,16 @@ language: python notifications: email: false -python: -- '2.7' -- '3.4' -- '3.5' +matrix: + include: + - python: 2.7 + - python: 3.4 + - python: 3.5 + - python: 3.6 + - python: 3.7 + dist: xenial + sudo: required + addons: apt: packages: diff --git a/README.rst b/README.rst index ffd73c17..0eceb538 100644 --- a/README.rst +++ b/README.rst @@ -199,6 +199,7 @@ The following versions of python is supported: - python3.4 - python3.5 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) - python3.6 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + - python3.7 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) ******* License diff --git a/setup.py b/setup.py index 3fff1b17..08c56670 100644 --- a/setup.py +++ b/setup.py @@ -57,6 +57,7 @@ def patch_options(self): 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', 'Topic :: Text Processing :: Markup :: XML' ], ) From d2601b8a11fb370aec8c5add13bee4cb011b8275 Mon Sep 17 00:00:00 2001 From: "Bernhard M. Wiedemann" Date: Sun, 25 Nov 2018 22:01:39 +0100 Subject: [PATCH 071/378] Sort input file list so that xmlsec.so builds in a reproducible way in spite of indeterministic filesystem readdir order and http://bugs.python.org/issue30461 See https://reproducible-builds.org/ for why this is good. --- xmlsec_setupinfo.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py index 69bd2a3a..bcfbd321 100644 --- a/xmlsec_setupinfo.py +++ b/xmlsec_setupinfo.py @@ -34,7 +34,7 @@ def description(): def sources(): - return glob.glob(os.path.join(get_base_dir(), "src", "*.c")) + return sorted(glob.glob(os.path.join(get_base_dir(), "src", "*.c"))) def define_macros(): From 5a0343ec253590b78ab52758f4e75bc67ada4008 Mon Sep 17 00:00:00 2001 From: Eduard Mucilianu Date: Fri, 4 Jan 2019 11:03:03 +0000 Subject: [PATCH 072/378] Update lxml requirement to 3.8 xmlsec will fail lxml versions prior to 3.8.0 with ```ImportError: lxml.etree does not export expected C function adoptExternalDocument``` --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index cd185c22..827d75e0 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ pkgconfig -lxml >= 3.0 +lxml >= 3.8.0 From 1e93b9d06701699bad302a1033dec30457ceff01 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 8 Jan 2019 23:03:10 +0300 Subject: [PATCH 073/378] Init exceptions module first --- src/main.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 490a37e6..d0591f16 100644 --- a/src/main.c +++ b/src/main.c @@ -228,6 +228,9 @@ PYENTRY_FUNC_NAME(void) } PYXMLSEC_DEBUGF("%p", module); + // init first, since PyXmlSec_Init may raise XmlSecError + if (PyXmlSec_ExceptionsModule_Init(module) < 0) goto ON_FAIL; + if (PyXmlSec_Init() < 0) goto ON_FAIL; if (PyModule_AddStringConstant(module, "__version__", STRINGIFY(MODULE_VERSION)) < 0) goto ON_FAIL; @@ -235,7 +238,6 @@ PYENTRY_FUNC_NAME(void) if (PyXmlSec_InitLxmlModule() < 0) goto ON_FAIL; /* Populate final object settings */ if (PyXmlSec_ConstantsModule_Init(module) < 0) goto ON_FAIL; - if (PyXmlSec_ExceptionsModule_Init(module) < 0) goto ON_FAIL; if (PyXmlSec_KeyModule_Init(module) < 0) goto ON_FAIL; if (PyXmlSec_TreeModule_Init(module) < 0) goto ON_FAIL; if (PyXmlSec_DSModule_Init(module) < 0) goto ON_FAIL; From eff75504d6728f49a4099f029ed1cec9163d5567 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 8 Jan 2019 23:05:48 +0300 Subject: [PATCH 074/378] Use module specific macro name --- src/main.c | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/main.c b/src/main.c index d0591f16..44d86034 100644 --- a/src/main.c +++ b/src/main.c @@ -15,11 +15,11 @@ #include #include -#define _FREE_NONE 0 -#define _FREE_XMLSEC 1 -#define _FREE_ALL 2 +#define _PYXMLSEC_FREE_NONE 0 +#define _PYXMLSEC_FREE_XMLSEC 1 +#define _PYXMLSEC_FREE_ALL 2 -static int free_mode = _FREE_NONE; +static int free_mode = _PYXMLSEC_FREE_NONE; #define MODULE_DOC "The tiny python wrapper around xmlsec1 (" XMLSEC_VERSION ") library" @@ -27,24 +27,24 @@ static int free_mode = _FREE_NONE; static void PyXmlSec_Free(int what) { PYXMLSEC_DEBUGF("free resources %d", what); switch (what) { - case _FREE_ALL: + case _PYXMLSEC_FREE_ALL: xmlSecCryptoAppShutdown(); - case _FREE_XMLSEC: + case _PYXMLSEC_FREE_XMLSEC: xmlSecShutdown(); } - free_mode = _FREE_NONE; + free_mode = _PYXMLSEC_FREE_NONE; } static int PyXmlSec_Init(void) { if (xmlSecInit() < 0) { PyXmlSec_SetLastError("cannot initialize xmlsec library."); - PyXmlSec_Free(_FREE_NONE); + PyXmlSec_Free(_PYXMLSEC_FREE_NONE); return -1; } if (xmlSecCheckVersion() != 1) { PyXmlSec_SetLastError("xmlsec library version mismatch."); - PyXmlSec_Free(_FREE_XMLSEC); + PyXmlSec_Free(_PYXMLSEC_FREE_XMLSEC); return -1; } @@ -58,7 +58,7 @@ static int PyXmlSec_Init(void) { PYXMLSEC_DEBUGF("dynamic crypto library: %s", cryptoLib); if (xmlSecCryptoDLLoadLibrary(cryptoLib) < 0) { PyXmlSec_SetLastError("cannot load crypto library for xmlsec."); - PyXmlSec_Free(_FREE_XMLSEC); + PyXmlSec_Free(_PYXMLSEC_FREE_XMLSEC); return -1; } #endif /* XMLSEC_CRYPTO_DYNAMIC_LOADING */ @@ -66,17 +66,17 @@ static int PyXmlSec_Init(void) { /* Init crypto library */ if (xmlSecCryptoAppInit(NULL) < 0) { PyXmlSec_SetLastError("cannot initialize crypto library application."); - PyXmlSec_Free(_FREE_XMLSEC); + PyXmlSec_Free(_PYXMLSEC_FREE_XMLSEC); return -1; } /* Init xmlsec-crypto library */ if (xmlSecCryptoInit() < 0) { PyXmlSec_SetLastError("cannot initialize crypto library."); - PyXmlSec_Free(_FREE_ALL); + PyXmlSec_Free(_PYXMLSEC_FREE_ALL); return -1; } - free_mode = _FREE_ALL; + free_mode = _PYXMLSEC_FREE_ALL; return 0; } @@ -96,7 +96,7 @@ static char PyXmlSec_PyShutdown__doc__[] = \ "This is called automatically upon interpreter termination and\n" "should not need to be called explicitly."; static PyObject* PyXmlSec_PyShutdown(PyObject* self) { - PyXmlSec_Free(_FREE_ALL); + PyXmlSec_Free(free_mode); Py_RETURN_NONE; } From f1c0836358ef2de211e1c854aae6ae23a376999f Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Tue, 8 Jan 2019 23:11:36 +0300 Subject: [PATCH 075/378] Unload cryptolib as well on shutdown module --- src/main.c | 30 ++++++++++++++++++++---------- 1 file changed, 20 insertions(+), 10 deletions(-) diff --git a/src/main.c b/src/main.c index 44d86034..de98a0b7 100644 --- a/src/main.c +++ b/src/main.c @@ -17,18 +17,35 @@ #define _PYXMLSEC_FREE_NONE 0 #define _PYXMLSEC_FREE_XMLSEC 1 -#define _PYXMLSEC_FREE_ALL 2 +#define _PYXMLSEC_FREE_CRYPTOLIB 2 +#define _PYXMLSEC_FREE_ALL 3 static int free_mode = _PYXMLSEC_FREE_NONE; #define MODULE_DOC "The tiny python wrapper around xmlsec1 (" XMLSEC_VERSION ") library" +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING +static const xmlChar* PyXmlSec_GetCryptoLibName() { +#if XMLSEC_VERSION_HEX > 308 + // xmlSecGetDefaultCrypto was introduced in version 1.2.21 + const xmlChar* cryptoLib = xmlSecGetDefaultCrypto(); +#else + const xmlChar* cryptoLib = (const xmlChar*) XMLSEC_CRYPTO; +#endif + PYXMLSEC_DEBUGF("dynamic crypto library: %s", cryptoLib); + return cryptoLib; +} +#endif // !XMLSEC_NO_CRYPTO_DYNAMIC_LOADING static void PyXmlSec_Free(int what) { PYXMLSEC_DEBUGF("free resources %d", what); switch (what) { case _PYXMLSEC_FREE_ALL: xmlSecCryptoAppShutdown(); + case _PYXMLSEC_FREE_CRYPTOLIB: +#ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING + xmlSecCryptoDLUnloadLibrary(PyXmlSec_GetCryptoLibName()); +#endif case _PYXMLSEC_FREE_XMLSEC: xmlSecShutdown(); } @@ -49,14 +66,7 @@ static int PyXmlSec_Init(void) { } #ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING -#if XMLSEC_VERSION_HEX > 308 - // xmlSecGetDefaultCrypto was introduced in version 1.2.21 - const xmlChar* cryptoLib = xmlSecGetDefaultCrypto(); -#else - const xmlChar* cryptoLib = (const xmlChar*) XMLSEC_CRYPTO; -#endif - PYXMLSEC_DEBUGF("dynamic crypto library: %s", cryptoLib); - if (xmlSecCryptoDLLoadLibrary(cryptoLib) < 0) { + if (xmlSecCryptoDLLoadLibrary(PyXmlSec_GetCryptoLibName()) < 0) { PyXmlSec_SetLastError("cannot load crypto library for xmlsec."); PyXmlSec_Free(_PYXMLSEC_FREE_XMLSEC); return -1; @@ -66,7 +76,7 @@ static int PyXmlSec_Init(void) { /* Init crypto library */ if (xmlSecCryptoAppInit(NULL) < 0) { PyXmlSec_SetLastError("cannot initialize crypto library application."); - PyXmlSec_Free(_PYXMLSEC_FREE_XMLSEC); + PyXmlSec_Free(_PYXMLSEC_FREE_CRYPTOLIB); return -1; } From 1e46b9851fc7877cf6c6242ecc54dae764f0e986 Mon Sep 17 00:00:00 2001 From: Bulat Gaifullin Date: Wed, 9 Jan 2019 01:04:11 +0300 Subject: [PATCH 076/378] Fix segfault on encrypt malformed document --- src/enc.c | 10 +- tests/data/enc-bad-in.xml | 208 ++++++++++++++++++++++++++++++++++++++ tests/test_enc.py | 21 ++++ 3 files changed, 238 insertions(+), 1 deletion(-) create mode 100644 tests/data/enc-bad-in.xml diff --git a/src/enc.c b/src/enc.c index bb5a6833..9db0b1b8 100644 --- a/src/enc.c +++ b/src/enc.c @@ -177,7 +177,11 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; // if n has references, it will not be deleted - Py_DECREF(PyXmlSec_elementFactory(doc, n)); + PyXmlSec_LxmlElementPtr* elem = PyXmlSec_elementFactory(doc, n); + if (NULL == elem) + xmlFreeNode(n); + else + Py_DECREF(elem); n = nn; } ctx->replacedNodeList = NULL; @@ -242,6 +246,9 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* Py_END_ALLOW_THREADS; PyXmlSec_ClearReplacedNodes(ctx->handle, node->_doc); + if (NULL != PyErr_Occurred()) { + goto ON_FAIL; + } if (rv != 0) { if (rv > 0) { @@ -253,6 +260,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* } xmlFree(tmpType); + PYXMLSEC_DEBUGF("%p: encrypt_xml - ok", self); return (PyObject*)PyXmlSec_elementFactory(node->_doc, xnew_node != NULL ? xnew_node : template->_c_node); ON_FAIL: diff --git a/tests/data/enc-bad-in.xml b/tests/data/enc-bad-in.xml new file mode 100644 index 00000000..460738fc --- /dev/null +++ b/tests/data/enc-bad-in.xml @@ -0,0 +1,208 @@ + + + + + + + + + MyNextCar + CreditApplication + MYNEXTCAR + VW + 409D03 + MyNextCar + + 2018-11-20T09:37:45Z + 7f0842cc-8d47-4955-be31-c61d07ee490b + + VW + + + + + + +
+ VCI_MNA_0000070250 + + + Car Chantilly +
+ 14839 Stonecroft Center Ct + Chantilly + VA + US + 20151 +
+ + + MyNextCar + MNA + + 7039562100 + + CAR +
+ N +
+ + + 2017 + Q7 + CAR + New + 0 + Prestige + + 64300.0 + MSRP + + + 64300.0 + Selling Price + + + + + 113456789 + NationalId + + + John + Q + Public + +
+ 999 Washington Ave + Apt #332 + Front Royal + VA + US + 22630 + 01 + 10 + Own +
+
+ 21 E 9th Ave + Boulder + CO + US + 80301-7577 + 07 + 11 + Own +
+ + 3032852402 + 3032852405 + 7203554444 + JohnQPublic@anydomain.org + + + 1967-07-31 + + 0 + + UPS +
+ 1775 Wiehle Ave. + Reston + VA + US + 20190 +
+ 9500.0 + Driver + 01 + 05 + Current +
+ + FedEx + 4000.00 + Driver + 04 + 09 + Previous + + 1252.52 + + 1500.00 + + + 1 + Consents to Credit Check + +
+ + + 123435325 + NationalId + + + Lisa + C + Public + +
+ 999 Lewis Street + Front Royal + VA + US + 22630 + 5 + 0 + Own +
+ + 5401110000 + 5401110073 + public@test.com + + + 1963-04-20 + + + Christendom College +
+ 999 Christendom Dr + Front Royal + VA + US + 22630 +
+ 6200.00 + Professor + 5 + 0 + Current +
+ 1252.52 + + 1 + Consents to Credit Check + +
+ + R + 0.00 + 66 + 5000.00 + INDIVCOAPP + 2000.00 + MyNextCar + + 1978 + Bonneville + Pontiac + Coupe + + +
+
+
+
+
+
diff --git a/tests/test_enc.py b/tests/test_enc.py index 726520f3..2f8c9d74 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -116,3 +116,24 @@ def check_decrypt(self, i): decrypted = ctx.decrypt(enc_data) self.assertIsNotNone(decrypted) self.assertEqual(self.load_xml("enc%d-in.xml" % i), root) + + + def check_no_segfault(self): + namespaces = { + 'soap': 'http://schemas.xmlsoap.org/soap/envelope/' + } + + manager = xmlsec.KeysManager() + key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + manager.add_key(key) + template = self.load_xml('enc-bad-in.xml') + enc_data = xmlsec.template.encrypted_data_create( + template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns='xenc') + xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) + key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') + enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_PKCS1) + xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) + data = template.find('soap:Body', namespaces=namespaces) + enc_ctx = xmlsec.EncryptionContext(manager) + enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 192, xmlsec.KeyDataType.SESSION) + self.assertRaises(Exception, enc_ctx.encrypt_xml(enc_data, data)) From da61a6a77e9ee54d7f0c4708a25007ea939efa99 Mon Sep 17 00:00:00 2001 From: Peter Ebden Date: Fri, 15 Feb 2019 13:39:14 +0000 Subject: [PATCH 077/378] Optionally disable RIPEMD160 and DSA via ifdefs --- src/constants.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/constants.c b/src/constants.c index 81f94560..a23dfb78 100644 --- a/src/constants.c +++ b/src/constants.c @@ -416,7 +416,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEncryptedKey, "ENCRYPTEDKEY") PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataAes, "AES") PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDes, "DES") +#ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDsa, "DSA") +#endif #if XMLSEC_VERSION_HEX > 306 PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEcdsa, "ECDSA") #endif @@ -463,8 +465,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDes3Cbc, "DES3"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWDes3, "KW_DES3"); - +#ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDsaSha1, "DSA_SHA1"); +#endif #if XMLSEC_VERSION_HEX > 306 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha1, "ECDSA_SHA1"); @@ -475,7 +478,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #endif PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacMd5, "HMAC_MD5"); +#ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacRipemd160, "HMAC_RIPEMD160"); +#endif PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha1, "HMAC_SHA1"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha224, "HMAC_SHA224"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha256, "HMAC_SHA256"); @@ -483,7 +488,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha512, "HMAC_SHA512"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaMd5, "RSA_MD5"); +#ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaRipemd160, "RSA_RIPEMD160"); +#endif PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha1, "RSA_SHA1"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha224, "RSA_SHA224"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaSha256, "RSA_SHA256"); @@ -493,7 +500,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaOaep, "RSA_OAEP"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformMd5, "MD5"); +#ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRipemd160, "RIPEMD160"); +#endif PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha1, "SHA1"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha224, "SHA224"); From cc7735b45d03a1dc82137daed4a1b56faa56b2c4 Mon Sep 17 00:00:00 2001 From: Ryan Leckey Date: Mon, 18 Mar 2019 11:52:22 -0700 Subject: [PATCH 078/378] Update deploy.password to hopefully fix #89 --- .travis.yml | 10 +++------- 1 file changed, 3 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 381da47f..398c0b57 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,7 +3,6 @@ sudo: false language: python notifications: email: false - matrix: include: - python: 2.7 @@ -13,7 +12,6 @@ matrix: - python: 3.7 dist: xenial sudo: required - addons: apt: packages: @@ -30,11 +28,9 @@ install: - travis_retry pip install -e "." - pip list script: py.test -v tests - before_deploy: - - travis_retry pip install Sphinx - - python setup.py build_sphinx - +- travis_retry pip install Sphinx +- python setup.py build_sphinx deploy: skip_cleanup: true skip_upload_docs: false @@ -45,4 +41,4 @@ deploy: distributions: sdist bdist_wheel python: '2.7' password: - secure: Gq9Ut9FATKUSVoaTTSeecN8kWxRQjTe4K+gK/gKuRJqWzYPOG9AhCq2Nxd3rwlWedPWpfoQwmlCuCma68npVQZnsJqyNYmEUBp4xjgDXOR12q2jDlgT0SH5V23ysJydA+c5QuHGXz7INxBTSwCjD+xBe2WXRxp9RJoi8kLloFt0= + secure: KNBbGaiAWirptxcuLjqNVgQ9E3jc75kj2+A5MRh+XvDVf6xFLAhrNg0+p/a3d+Tdap4/W5retxDdafLoMJ80ftyJFWV+lnrDxBhcrT686HGXPb0FCn58+Mho0RhM7CSHJIM8E85pVUV5E6QrmgmNWG8KKEaF3Vs5RJBhlP/g7Bg= From b396387079d126647e572ce7ce95e0714f21ae96 Mon Sep 17 00:00:00 2001 From: Calvin DeBoer Date: Mon, 8 Apr 2019 13:57:59 -0400 Subject: [PATCH 079/378] Spelling Fix --- doc/source/examples.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/source/examples.rst b/doc/source/examples.rst index e0427d75..830aaeb9 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -41,7 +41,7 @@ Encrypt # Encryption enc_ctx = xmlsec.EncryptionContext(manager) enc_ctx.key = xmlsec.Key.generate(xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession) - enc_datsa = enc_ctx.encrypt_xml(enc_data, data) + enc_data = enc_ctx.encrypt_xml(enc_data, data) enc_method = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) key_info = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs) enc_method = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) From e5cb1e25a8c59a5ee8697abda6e92b9d3648020b Mon Sep 17 00:00:00 2001 From: Sascha P Date: Fri, 19 Apr 2019 14:12:12 +0200 Subject: [PATCH 080/378] Added instructions for Alpine to README --- README.rst | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/README.rst b/README.rst index 0eceb538..f09b31ba 100644 --- a/README.rst +++ b/README.rst @@ -67,6 +67,14 @@ Mac brew install libxml2 libxmlsec1 +Alpine +^^^^^^ + +.. code-block:: bash + + apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec + + Automated --------- 1. **xmlsec** can be installed through `easy_install` or `pip`. From b36fbe07457935c74b57d5ff01a502823416c00e Mon Sep 17 00:00:00 2001 From: mschwager Date: Wed, 16 Oct 2019 11:09:58 -0600 Subject: [PATCH 081/378] Update constants docs --- doc/source/modules/constants.rst | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index a9b7c511..67f2d711 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -119,8 +119,8 @@ Transforms - *TransformKWAes128* - The AES 128 key wrap transform klass. - *TransformKWAes192* - The AES 192 key wrap transform klass. - *TransformKWAes256* - The AES 256 key wrap transform klass. -- *TransformDes3Cbc* - The Triple DES encryption transform klass. -- *TransformKWDes3* - The DES3 CBC cipher transform klass. +- *TransformDes3Cbc* - The DES3 CBC cipher transform klass. +- *TransformKWDes3* - The DES3 key wrap transform klass. - *TransformDsaSha1* - The DSA-SHA1 signature transform klass. - *TransformEcdsaSha1* - The ECDSA-SHA1 signature transform klass. - *TransformEcdsaSha224* - The ECDSA-SHA224 signature transform klass. @@ -142,7 +142,7 @@ Transforms - *TransformRsaSha384* - The RSA-SHA384 signature transform klass. - *TransformRsaSha512* - The RSA-SHA512 signature transform klass. - *TransformRsaPkcs1* - The RSA PKCS1 key transport transform klass. -- *TransformRsaOaep* - The RSA PKCS1 key transport transform klass. +- *TransformRsaOaep* - The RSA OAEP key transport transform klass. - *TransformMd5* - The MD5 digest transform klass. - *TransformRipemd160* - The RIPEMD160 digest transform klass. - *TransformSha1* - The SHA1 digest transform klass. From 4e1b7b27cefd986fd5f975370e7357bf583bd391 Mon Sep 17 00:00:00 2001 From: Taulant Dhami Date: Mon, 21 Oct 2019 10:55:44 -0400 Subject: [PATCH 082/378] Add pkg-config to Mac brew instructions fixes #92 --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index f09b31ba..79a8d97f 100644 --- a/README.rst +++ b/README.rst @@ -64,7 +64,7 @@ Mac .. code-block:: bash - brew install libxml2 libxmlsec1 + brew install libxml2 libxmlsec1 pkg-config Alpine From 715dd19ab62a25c75a78edca5c12c022aa31ca32 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 11:11:22 +0200 Subject: [PATCH 083/378] add rudimentary support for PEP 518, configure black + isort in pyproject.toml Signed-off-by: oleg.hoefling --- pyproject.toml | 33 +++++++++++++++++++++++++++++++++ 1 file changed, 33 insertions(+) create mode 100644 pyproject.toml diff --git a/pyproject.toml b/pyproject.toml new file mode 100644 index 00000000..636c52c9 --- /dev/null +++ b/pyproject.toml @@ -0,0 +1,33 @@ +[tool.black] +line_length = 130 +skip-string-normalization = true +target_version = ['py38'] +include = '\.pyi?$' +exclude = ''' + +( + /( + \.eggs # exclude a few common directories in the + | \.git # root of the project + | \.mypy_cache + | \.tox + | build + | dist + )/ +) +''' + +[tool.isort] +force_alphabetical_sort_within_sections = true +recursive = true +line_length = 130 +multi_line_output = 3 +include_trailing_comma = true +force_grid_wrap = 0 +use_parentheses = true +combine_as_imports = true +known_first_party = ['xmlsec'] +known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] + +[build-system] +requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4'] From bafe91d98b969f4897040f91540fb95e8d2e2d34 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 11:17:11 +0200 Subject: [PATCH 084/378] use setuptools-scm for version calculations, add setuptools-scm support for older pip versions Signed-off-by: oleg.hoefling --- setup.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/setup.py b/setup.py index 08c56670..15f48ecf 100644 --- a/setup.py +++ b/setup.py @@ -1,5 +1,4 @@ -from setuptools import setup -from setuptools import Extension +from setuptools import Extension, setup from setuptools.command import build_ext import xmlsec_setupinfo @@ -31,11 +30,11 @@ def patch_options(self): setup( name=xmlsec_setupinfo.name(), - version=xmlsec_setupinfo.version(), + use_scm_version=True, description=xmlsec_setupinfo.description(), ext_modules=[_xmlsec], cmdclass={'build_ext': BuildExt}, - setup_requires=xmlsec_setupinfo.requirements(), + setup_requires=xmlsec_setupinfo.requirements() + ['setuptools_scm[toml]>=3.4'], install_requires=xmlsec_setupinfo.requirements(), author="Bulat Gaifullin", author_email='support@mehcode.com', @@ -58,6 +57,6 @@ def patch_options(self): 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', - 'Topic :: Text Processing :: Markup :: XML' + 'Topic :: Text Processing :: Markup :: XML', ], ) From 68ecb13f7f504d8bb015f66fafac3cd7769398e1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 11:49:01 +0200 Subject: [PATCH 085/378] travis: drop 3.4, add 3.8 Signed-off-by: oleg.hoefling --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 398c0b57..5f824587 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,12 +6,14 @@ notifications: matrix: include: - python: 2.7 - - python: 3.4 - python: 3.5 - python: 3.6 - python: 3.7 dist: xenial sudo: required + - python: 3.8 + dist: xenial + sudo: required addons: apt: packages: @@ -21,8 +23,6 @@ addons: - libxmlsec1-openssl - libxslt1-dev - pkg-config -before_install: -- echo "${TRAVIS_TAG:-1.0.1.dev}" >version.txt install: - travis_retry pip install -r requirements-test.txt - travis_retry pip install -e "." From 373668eed8e6d6fdb0851b69a998050783115d0a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 12:15:27 +0200 Subject: [PATCH 086/378] record coverage in tests, add codecov integration Signed-off-by: oleg.hoefling --- .travis.yml | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 5f824587..b876cecb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,12 @@ matrix: - python: 3.8 dist: xenial sudo: required +env: + global: + - CFLAGS=-coverage + - LDFLAGS=-coverage -lgcov + - PYXMLSEC_TEST_ITERATIONS=50 + addons: apt: packages: @@ -23,11 +29,16 @@ addons: - libxmlsec1-openssl - libxslt1-dev - pkg-config + - lcov install: -- travis_retry pip install -r requirements-test.txt +- travis_retry pip install coverage codecov -r requirements-test.txt - travis_retry pip install -e "." - pip list -script: py.test -v tests +script: coverage run -m pytest -v tests +after_success: +- lcov --capture --directory . --output-file coverage.info +- lcov --list coverage.info +- codecov --file coverage.info before_deploy: - travis_retry pip install Sphinx - python setup.py build_sphinx From e094330abc0cd26efb5b2b52704ecce97bea8abc Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 12:30:04 +0200 Subject: [PATCH 087/378] add codecov badge to readme Signed-off-by: oleg.hoefling --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 79a8d97f..66b95a9c 100644 --- a/README.rst +++ b/README.rst @@ -5,6 +5,8 @@ python-xmlsec :target: https://travis-ci.org/mehcode/python-xmlsec .. image:: https://ci.appveyor.com/api/projects/status/20rtt2wv96gag9cy?svg=true :target: https://ci.appveyor.com/project/bgaifullin/python-xmlsec +.. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg + :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg :target: https://pypi.python.org/pypi/xmlsec .. image:: https://img.shields.io/badge/docs-latest-green.svg From 7929848f5aa387ac17d30e49bc8c70ccba928699 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Tue, 5 May 2020 22:18:35 +0200 Subject: [PATCH 088/378] move code examples in docs to file system, test whether the examples are runnable Signed-off-by: oleg.hoefling --- doc/source/examples.rst | 93 ++-------------------------- doc/source/examples/decrypt.py | 12 ++++ doc/source/examples/enc1-doc.xml | 7 +++ doc/source/examples/enc1-res.xml | 22 +++++++ doc/source/examples/encrypt.py | 40 ++++++++++++ doc/source/examples/rsacert.pem | 83 +++++++++++++++++++++++++ doc/source/examples/rsakey.pem | 27 ++++++++ doc/source/examples/rsapub.pem | 9 +++ doc/source/examples/sign.py | 12 ++++ doc/source/examples/sign1-res.xml | 31 ++++++++++ doc/source/examples/sign1-tmpl.xml | 26 ++++++++ doc/source/examples/sign_binary.py | 10 +++ doc/source/examples/verify.py | 13 ++++ doc/source/examples/verify_binary.py | 11 ++++ tests/test_doc_examples.py | 44 +++++++++++++ 15 files changed, 353 insertions(+), 87 deletions(-) create mode 100644 doc/source/examples/decrypt.py create mode 100644 doc/source/examples/enc1-doc.xml create mode 100644 doc/source/examples/enc1-res.xml create mode 100644 doc/source/examples/encrypt.py create mode 100644 doc/source/examples/rsacert.pem create mode 100644 doc/source/examples/rsakey.pem create mode 100644 doc/source/examples/rsapub.pem create mode 100644 doc/source/examples/sign.py create mode 100644 doc/source/examples/sign1-res.xml create mode 100644 doc/source/examples/sign1-tmpl.xml create mode 100644 doc/source/examples/sign_binary.py create mode 100644 doc/source/examples/verify.py create mode 100644 doc/source/examples/verify_binary.py create mode 100644 tests/test_doc_examples.py diff --git a/doc/source/examples.rst b/doc/source/examples.rst index 830aaeb9..b5f9bb95 100644 --- a/doc/source/examples.rst +++ b/doc/source/examples.rst @@ -3,114 +3,33 @@ Examples Decrypt ------- -.. code:: python - - from lxml import etree - import xmlsec - - manager = xmlsec.KeysManager() - key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) - manager.add_key(key) - enc_ctx = xmlsec.EncryptionContext(manager) - root = etree.parse("enc1-res.xml").getroot() - enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.constants.EncNs) - decrypted = enc_ctx.decrypt(enc_data) - print(etree.tostring(decrypted)) +.. literalinclude:: examples/decrypt.py Encrypt ------- -.. code:: python - - from lxml import etree - import xmlsec - - manager = xmlsec.KeysManager() - key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None) - manager.add_key(key) - template = etree.parse('enc1-doc.xml').getroot() - enc_data = xmlsec.template.encrypted_data_create( - template, xmlsec.constants.TransformAes128Cbc, type=xmlsec.constants.TypeEncContent, ns="xenc") - xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") - enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) - xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) - data = template.find('./Data') - - # Encryption - enc_ctx = xmlsec.EncryptionContext(manager) - enc_ctx.key = xmlsec.Key.generate(xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession) - enc_data = enc_ctx.encrypt_xml(enc_data, data) - enc_method = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) - key_info = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs) - enc_method = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) - cipher_value = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs) - print(etree.tostring(cipher_value)) +.. literalinclude:: examples/encrypt.py Sign ---- -.. code:: python - - from lxml import etree - import xmlsec - - template = etree.parse('sign1-tmpl.xml').getroot() - - signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) - ctx = xmlsec.SignatureContext() - key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) - ctx.key = key - ctx.sign(signature_node) - print(etree.tostring(template)) +.. literalinclude:: examples/sign.py Sign-Binary ----------- -.. code:: python - - from lxml import etree - import xmlsec - - ctx = xmlsec.SignatureContext() - key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) - ctx.key = key - data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' - sign = ctx.sign_binary(data, xmlsec.constants.TransformRsaSha1) - print(sign) +.. literalinclude:: examples/sign_binary.py Verify ------ -.. code:: python - from lxml import etree - import xmlsec - - template = etree.parse('sign1-res.xml').getroot() - xmlsec.tree.add_ids(template, ["ID"]) - signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) - # Create a digital signature context (no key manager is needed). - ctx = xmlsec.SignatureContext() - key = xmlsec.Key.from_file('rsapub.pem', xmlsec.constants.KeyDataFormatPem) - # Set the key on the context. - ctx.key = key - ctx.verify(signature_node) +.. literalinclude:: examples/verify.py Verify-Binary ------------- -.. code:: python - - from lxml import etree - import xmlsec - - ctx = xmlsec.SignatureContext() - key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) - ctx.key = key - data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' - sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" - ctx.verify_binary(data, xmlsec.constants.TransformRsaSha1, sign) +.. literalinclude:: examples/verify_binary.py diff --git a/doc/source/examples/decrypt.py b/doc/source/examples/decrypt.py new file mode 100644 index 00000000..e107756f --- /dev/null +++ b/doc/source/examples/decrypt.py @@ -0,0 +1,12 @@ +from lxml import etree + +import xmlsec + +manager = xmlsec.KeysManager() +key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) +manager.add_key(key) +enc_ctx = xmlsec.EncryptionContext(manager) +root = etree.parse("enc1-res.xml").getroot() +enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.constants.EncNs) +decrypted = enc_ctx.decrypt(enc_data) +print(etree.tostring(decrypted)) diff --git a/doc/source/examples/enc1-doc.xml b/doc/source/examples/enc1-doc.xml new file mode 100644 index 00000000..39f8d761 --- /dev/null +++ b/doc/source/examples/enc1-doc.xml @@ -0,0 +1,7 @@ + + + +Hello, World! + diff --git a/doc/source/examples/enc1-res.xml b/doc/source/examples/enc1-res.xml new file mode 100644 index 00000000..ab0b1a6c --- /dev/null +++ b/doc/source/examples/enc1-res.xml @@ -0,0 +1,22 @@ + + + + + + + + +UrTgE0UxQa8xevs4SyRA0rsibEz/ZFDjCBD+t4pKSdajB/cefYObZzqq2l41Q6R/ +tqYLht5hEBh26AHfjmQSJAL+eChXOt/EaOf63zzJedO90HGqIQyzOeOPURAl3Li8 +ivPyLVyocJDeVNeh7W+7kYwpFQ6PLuQxWsFFQXVoRAWbXHpZkSzVheR+5RpYJRTb +1UYXKxu8jg4NqbjucVMDIxUOzsVCDRyk8R8sQrM7D/H/N0y7DAY8oX/WZ45xLwUy +DY/U86tTpTn95NwHD10SLyrL6rpXdbEuoIQHhWLwV9uQxnJA/Pn1KZ+xXK/fePfP +26PBo/hUrN5pm5U8ycc4iw== + + + + +2pb5Mxd0f+AW56Cs3MfQ9HJkUVeliSi1hVCNCVHTKeMyC2VL6lPhQ9+L01aSeTSY + + + diff --git a/doc/source/examples/encrypt.py b/doc/source/examples/encrypt.py new file mode 100644 index 00000000..595b63c9 --- /dev/null +++ b/doc/source/examples/encrypt.py @@ -0,0 +1,40 @@ +from lxml import etree + +import xmlsec + +manager = xmlsec.KeysManager() +key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None) +manager.add_key(key) +template = etree.parse('enc1-doc.xml').getroot() +enc_data = xmlsec.template.encrypted_data_create( + template, + xmlsec.constants.TransformAes128Cbc, + type=xmlsec.constants.TypeEncElement, + ns="xenc", +) + +xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) +key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") +enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) +xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) +data = template.find('./Data') + +# Encryption +enc_ctx = xmlsec.EncryptionContext(manager) +enc_ctx.key = xmlsec.Key.generate( + xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession +) +enc_data = enc_ctx.encrypt_xml(enc_data, data) +enc_method = xmlsec.tree.find_child( + enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs +) +key_info = xmlsec.tree.find_child( + enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs +) +enc_method = xmlsec.tree.find_node( + key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs +) +cipher_value = xmlsec.tree.find_node( + key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs +) +print(etree.tostring(cipher_value)) diff --git a/doc/source/examples/rsacert.pem b/doc/source/examples/rsacert.pem new file mode 100644 index 00000000..e8a68228 --- /dev/null +++ b/doc/source/examples/rsacert.pem @@ -0,0 +1,83 @@ +Certificate: + Data: + Version: 3 (0x2) + Serial Number: 5 (0x5) + Signature Algorithm: md5WithRSAEncryption + Issuer: C=US, ST=California, L=Sunnyvale, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Root Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + Validity + Not Before: Mar 31 04:02:22 2003 GMT + Not After : Mar 28 04:02:22 2013 GMT + Subject: C=US, ST=California, O=XML Security Library (http://www.aleksey.com/xmlsec), OU=Examples RSA Certificate, CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + Subject Public Key Info: + Public Key Algorithm: rsaEncryption + RSA Public Key: (2048 bit) + Modulus (2048 bit): + 00:97:b8:fe:b4:3f:83:35:78:16:89:04:ec:2b:61: + 8c:bf:c4:5f:00:81:4a:45:e6:d9:cd:e9:e2:3c:97: + 3b:45:ad:aa:e6:8d:0b:77:71:07:01:4f:7c:f9:7d: + e2:19:aa:dd:91:59:f4:f1:cf:3d:ba:78:46:96:11: + 9c:b6:5b:46:39:73:55:23:aa:f7:9e:00:5c:e5:e9: + 49:ec:3b:9c:3f:84:99:3a:90:ad:df:7e:64:86:c6: + 26:72:ce:31:08:79:7e:13:15:b8:e5:bf:d6:56:02: + 8d:60:21:4c:27:18:64:fb:fb:55:70:f6:33:bd:2f: + 55:70:d5:5e:7e:99:ae:a4:e0:aa:45:47:13:a8:30: + d5:a0:8a:9d:cc:20:ec:e4:8e:51:c9:54:c5:7f:3e: + 66:2d:74:bf:a3:7a:f8:f3:ec:94:57:39:b4:ac:00: + 75:62:61:54:b4:d0:e0:52:86:f8:5e:77:ec:50:43: + 9c:d2:ba:a7:8c:62:5a:bc:b2:fe:f3:cc:62:7e:23: + 60:6b:c7:51:49:37:78:7e:25:15:30:ab:fa:b4:ae: + 25:8f:22:fc:a3:48:7f:f2:0a:8a:6e:e0:fe:8d:f0: + 01:ed:c6:33:cc:6b:a1:fd:a6:80:ef:06:8c:af:f6: + 40:3a:8e:42:14:20:61:12:1f:e3:fc:05:b1:05:d5: + 65:c3 + Exponent: 65537 (0x10001) + X509v3 extensions: + X509v3 Basic Constraints: + CA:FALSE + Netscape Comment: + OpenSSL Generated Certificate + X509v3 Subject Key Identifier: + 24:84:2C:F2:D4:59:20:62:8B:2E:5C:86:90:A3:AA:30:BA:27:1A:9C + X509v3 Authority Key Identifier: + keyid:B4:B9:EF:9A:E6:97:0E:68:65:1E:98:CE:FA:55:0D:89:06:DB:4C:7C + DirName:/C=US/ST=California/L=Sunnyvale/O=XML Security Library (http://www.aleksey.com/xmlsec)/OU=Root Certificate/CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com + serial:00 + + Signature Algorithm: md5WithRSAEncryption + b5:3f:9b:32:31:4a:ff:2f:84:3b:a8:9b:11:5c:a6:5c:f0:76: + 52:d9:6e:f4:90:ad:fa:0d:90:c1:98:d5:4a:12:dd:82:6b:37: + e8:d9:2d:62:92:c9:61:37:98:86:8f:a4:49:6a:5e:25:d0:18: + 69:30:0f:98:8f:43:58:89:31:b2:3b:05:e2:ef:c7:a6:71:5f: + f7:fe:73:c5:a7:b2:cd:2e:73:53:71:7d:a8:4c:68:1a:32:1b: + 5e:48:2f:8f:9b:7a:a3:b5:f3:67:e8:b1:a2:89:4e:b2:4d:1b: + 79:9c:ff:f0:0d:19:4f:4e:b1:03:3d:99:f0:44:b7:8a:0b:34: + 9d:83 +-----BEGIN CERTIFICATE----- +MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X +DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy +eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt +cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf +BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt +quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E +mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg +qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53 +7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w +Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG +A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp +ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw +MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA +MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY +1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn +ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL +NJ2D +-----END CERTIFICATE----- diff --git a/doc/source/examples/rsakey.pem b/doc/source/examples/rsakey.pem new file mode 100644 index 00000000..55d2fd9b --- /dev/null +++ b/doc/source/examples/rsakey.pem @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAl7j+tD+DNXgWiQTsK2GMv8RfAIFKRebZzeniPJc7Ra2q5o0L +d3EHAU98+X3iGardkVn08c89unhGlhGctltGOXNVI6r3ngBc5elJ7DucP4SZOpCt +335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk+/tVcPYzvS9VcNVefpmupOCqRUcT +qDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yUVzm0rAB1YmFUtNDgUob4XnfsUEOc +0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6tK4ljyL8o0h/8gqKbuD+jfAB7cYz +zGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVlwwIDAQABAoIBAQCAvt6DnZF9gdW9 +l4vAlBqXb88d4phgELCp5tmviLUnP2NSGEWuqR7Eoeru2z9NgIxblvYfazh6Ty22 +kmNk6rcAcTnB9oYAcVZjUj8EUuEXlTFhXPvuNpafNu3RZd59znqJP1mSu+LpQWku +NZMlabHnkTLDlGf7FXtvL9/rlgV4qk3QcDVF793JFszWrtK3mnld3KHQ6cuo9iSm +0rQKtkDjeHsRell8qTQvfBsgG1q2bv8QWT45/eQrra9mMbGTr3DbnXvoeJmTj1VN +XJV7tBNllxxPahlYMByJaf/Tuva5j6HWUEIfYky5ihr2z1P/fNQ2OSCM6SQHpkiG +EXQDueXBAoGBAMfW7KcmToEQEcTiqfey6C1LOLoemcX0/ROUktPq/5JQJRRrT4t7 +XevLX0ed8sLyR5T29XQtdnuV0DJfvcJD+6ZwfOcQ+f6ZzCaNXJP97JtEt5kSWY01 +Ei+nphZ0RFvPb04V3qDU9dElU26GR36CRBYJyM2WQPx4v+/YyDSZH9kLAoGBAMJc +ZBU8pRbIia/FFOHUlS3v5P18nVmXyOd0fvRq0ZelaQCebTZ4K9wjnCfw//yzkb2Z +0vZFNB+xVBKB0Pt6nVvnSNzxdQ8EAXVFwHtXa25FUyP2RERQgTvmajqmgWjZsDYp +6GHcK3ZhmdmscQHF/Q2Uo4scvBcheahm9IXiNskpAoGAXelEgTBhSAmTMCEMmti6 +fz6QQ/bJcNu2apMxhOE0hT+gjT34vaWV9481EWTKho5w0TJVGumaem1mz6VqeXaV +Nhw6tiOmN91ysNNRpEJ6BGWAmjCjYNaF21s/k+HDlhmfRuTEIHSzqDuQP6pewrbY +5Dpo4SQxGfRsznvjacRj0Q0CgYBN247oBvQnDUxCkhNMZ8kersOvW5T4x9neBge5 +R3UQZ12Jtu0O7dK8C7PJODyDcTeHmTAuIQjBTVrdUw1xP+v7XcoNX9hBnJws6zUw +85MAiFrGxCcSqqEqaqHRPtQGOXXiLKV/ViA++tgTn4VhbXtyTkG5P1iFd45xjFSV +sUm7CQKBgDn92tHxzePly1L1mK584TkVryx4cP9RFHpebnmNduGwwjnRuYipoj8y +pPPAkVbbaA3f9OB2go48rN0Ft9nHdlqgh9BpIKCVtkIb1XN0K3Oa/8BW8W/GAiNG +HJcsrOtIrGVRdlyJG6bDaN8T49DnhOcsqMbf+IkIvfh50VeE9L/e +-----END RSA PRIVATE KEY----- diff --git a/doc/source/examples/rsapub.pem b/doc/source/examples/rsapub.pem new file mode 100644 index 00000000..838a346d --- /dev/null +++ b/doc/source/examples/rsapub.pem @@ -0,0 +1,9 @@ +-----BEGIN PUBLIC KEY----- +MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAl7j+tD+DNXgWiQTsK2GM +v8RfAIFKRebZzeniPJc7Ra2q5o0Ld3EHAU98+X3iGardkVn08c89unhGlhGctltG +OXNVI6r3ngBc5elJ7DucP4SZOpCt335khsYmcs4xCHl+ExW45b/WVgKNYCFMJxhk ++/tVcPYzvS9VcNVefpmupOCqRUcTqDDVoIqdzCDs5I5RyVTFfz5mLXS/o3r48+yU +Vzm0rAB1YmFUtNDgUob4XnfsUEOc0rqnjGJavLL+88xifiNga8dRSTd4fiUVMKv6 +tK4ljyL8o0h/8gqKbuD+jfAB7cYzzGuh/aaA7waMr/ZAOo5CFCBhEh/j/AWxBdVl +wwIDAQAB +-----END PUBLIC KEY----- diff --git a/doc/source/examples/sign.py b/doc/source/examples/sign.py new file mode 100644 index 00000000..4529bc8a --- /dev/null +++ b/doc/source/examples/sign.py @@ -0,0 +1,12 @@ +from lxml import etree + +import xmlsec + +template = etree.parse('sign1-tmpl.xml').getroot() + +signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) +ctx = xmlsec.SignatureContext() +key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) +ctx.key = key +ctx.sign(signature_node) +print(etree.tostring(template)) diff --git a/doc/source/examples/sign1-res.xml b/doc/source/examples/sign1-res.xml new file mode 100644 index 00000000..f46ac1f4 --- /dev/null +++ b/doc/source/examples/sign1-res.xml @@ -0,0 +1,31 @@ + + + + + Hello, World! + + + + + + + + + + + 9H/rQr2Axe9hYTV2n/tCp+3UIQQ= + + + Mx4psIy9/UY+u8QBJRDrwQWKRaCGz0WOVftyDzAe6WHAFSjMNr7qb2ojq9kdipT8 +Oub5q2OQ7mzdSLiiejkrO1VeqM/90yEIGI4En6KEB6ArEzw+iq4N1wm6EptcyxXx +M9StAOOa9ilWYqR9Tfx3SW1urUIuKYgUitxsONiUHBVaW6HeX51bsXoTF++4ZI+D +jiPBjN4HHmr0cbJ6BXk91S27ffZIfp1Qj5nL9onFLUGbR6EFgu2luiRzQbPuM2tP +XxyI7GZ8AfHnRJK28ARvBC9oi+O1ej20S79CIV7gdBxbLbFprozBHAwOEC57YgJc +x+YEjSjcO7SBIR1FiUA7pw== + + rsakey.pem + + + diff --git a/doc/source/examples/sign1-tmpl.xml b/doc/source/examples/sign1-tmpl.xml new file mode 100644 index 00000000..0a0cd442 --- /dev/null +++ b/doc/source/examples/sign1-tmpl.xml @@ -0,0 +1,26 @@ + + + + + Hello, World! + + + + + + + + + + + + + + + + + + + diff --git a/doc/source/examples/sign_binary.py b/doc/source/examples/sign_binary.py new file mode 100644 index 00000000..4e6c0e00 --- /dev/null +++ b/doc/source/examples/sign_binary.py @@ -0,0 +1,10 @@ +from lxml import etree + +import xmlsec + +ctx = xmlsec.SignatureContext() +key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) +ctx.key = key +data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' +sign = ctx.sign_binary(data, xmlsec.constants.TransformRsaSha1) +print(sign) diff --git a/doc/source/examples/verify.py b/doc/source/examples/verify.py new file mode 100644 index 00000000..8629c550 --- /dev/null +++ b/doc/source/examples/verify.py @@ -0,0 +1,13 @@ +from lxml import etree + +import xmlsec + +template = etree.parse('sign1-res.xml').getroot() +xmlsec.tree.add_ids(template, ["ID"]) +signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) +# Create a digital signature context (no key manager is needed). +ctx = xmlsec.SignatureContext() +key = xmlsec.Key.from_file('rsapub.pem', xmlsec.constants.KeyDataFormatPem) +# Set the key on the context. +ctx.key = key +ctx.verify(signature_node) diff --git a/doc/source/examples/verify_binary.py b/doc/source/examples/verify_binary.py new file mode 100644 index 00000000..06c2b727 --- /dev/null +++ b/doc/source/examples/verify_binary.py @@ -0,0 +1,11 @@ +from lxml import etree + +import xmlsec + +ctx = xmlsec.SignatureContext() +key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) +ctx.key = key + +data = b'\xa8f4dP\x82\x02\xd3\xf5.\x02\xc1\x03\xef\xc4\x86\xabC\xec\xb7>\x8e\x1f\xa3\xa3\xc5\xb9qc\xc2\x81\xb1-\xa4B\xdf\x03>\xba\xd1' +sign = b"h\xcb\xb1\x82\xfa`e\x89x\xe5\xc5ir\xd6\xd1Q\x9a\x0b\xeaU_G\xcc'\xa4c\xa3>\x9b27\xbf^`\xa7p\xfb\x98\xcb\x81\xd2\xb1\x0c'\x9d\xe2\n\xec\xb2<\xcf@\x98=\xe0}O8}fy\xc2\xc4\xe9\xec\x87\xf6\xc1\xde\xfd\x96*o\xab\xae\x12\xc9{\xcc\x0e\x93y\x9a\x16\x80o\x92\xeb\x02^h|\xa0\x9b<\x99_\x97\xcb\xe27\xe9u\xc3\xfa_\xcct/sTb\xa0\t\xd3\x93'\xb4\xa4\x0ez\xcbL\x14D\xdb\xe3\x84\x886\xe9J[\xe7\xce\xc0\xb1\x99\x07\x17{\xc6:\xff\x1dt\xfd\xab^2\xf7\x9e\xa4\xccT\x8e~b\xdb\x9a\x04\x04\xbaM\xfa\xbd\xec)z\xbb\x89\xd7\xb2Q\xac\xaf\x13\xdcD\xcd\n6\x92\xfao\xb9\xd9\x96$\xce\xa6\xcf\xf8\xe4Bb60\xf5\xd2a\xb1o\x8c\x0f\x8bl\x88vh\xb5h\xfa\xfa\xb66\xedQ\x10\xc4\xef\xfa\x81\xf0\xc9.^\x98\x1ePQS\x9e\xafAy\x90\xe4\x95\x03V\xc2\xa0\x18\xa5d\xc2\x15*\xb6\xd7$\xc0\t2\xa1" +ctx.verify_binary(data, xmlsec.constants.TransformRsaSha1, sign) diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py new file mode 100644 index 00000000..bca6df48 --- /dev/null +++ b/tests/test_doc_examples.py @@ -0,0 +1,44 @@ +"""Run tests over code examples in the documentation.""" + +import contextlib +import os +import runpy +import sys + +import pytest + +if sys.version_info >= (3, 4): + from pathlib import Path +else: # python2.7 compat + from _pytest.pathlib import Path + + +examples_dir = Path(__file__, '../../doc/source/examples').resolve() +examples = sorted(examples_dir.glob('*.py')) + + +@contextlib.contextmanager +def cd(where_to: Path): + """ + Temporarily change the working directory. + + Restore the current working dir after exiting the context. + """ + curr = Path.cwd() + try: + os.chdir(str(where_to)) + yield + finally: + os.chdir(str(curr)) + + +@pytest.mark.parametrize('example', examples, ids=lambda p: p.name) +def test_doc_example(example): + """ + Verify example scripts included in the docs are up to date. + + Execute each script in :file:`docs/source/examples`, + not raising any errors is good enough. + """ + with cd(example.parent): + runpy.run_path(str(example)) From 30ec9dbda591cb79c73c007a329d260928e73789 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 17:04:27 +0200 Subject: [PATCH 089/378] don't use type hints until python 2.7 is dropped Signed-off-by: oleg.hoefling --- tests/test_doc_examples.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index bca6df48..2fc490f3 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -18,7 +18,7 @@ @contextlib.contextmanager -def cd(where_to: Path): +def cd(where_to): """ Temporarily change the working directory. From a7446179730c30e0ec0fbef4ffaad62085ea5acf Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 17:13:25 +0200 Subject: [PATCH 090/378] old pytest versions don't have pathlib backport, but we need 4.6 to be able to run tests on python 2.7 Signed-off-by: oleg.hoefling --- requirements-test.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements-test.txt b/requirements-test.txt index 26b77f68..7c3bc70f 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,2 +1,2 @@ -r requirements.txt -pytest +pytest>=4.6.9 From 3bcfc23bd2f45bfd8d577e5a79b1b4aae226f8fb Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 17:50:36 +0200 Subject: [PATCH 091/378] travis: add 3.9-dev build Signed-off-by: oleg.hoefling --- .travis.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.travis.yml b/.travis.yml index b876cecb..f119af4e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,9 @@ matrix: - python: 3.8 dist: xenial sudo: required + - python: 3.9-dev + dist: xenial + sudo: required env: global: - CFLAGS=-coverage From 8ecbcfe645a0fe7372aab0d19a0cbbad3856f6a5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:20:35 +0200 Subject: [PATCH 092/378] add tests for constants string and raw string representation Signed-off-by: oleg.hoefling --- setup.cfg | 3 +++ tests/test_constants.py | 41 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 tests/test_constants.py diff --git a/setup.cfg b/setup.cfg index 3b305822..ada30e9b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -14,3 +14,6 @@ all_files = 1 [upload_docs] upload-dir = doc/build/html + +[flake8] +max-line-length = 130 diff --git a/tests/test_constants.py b/tests/test_constants.py new file mode 100644 index 00000000..857a1cdd --- /dev/null +++ b/tests/test_constants.py @@ -0,0 +1,41 @@ +"""Test constants from :mod:`xmlsec.constants` module.""" + +import xmlsec +from hypothesis import given, strategies + + +def _constants(typename): + return list( + sorted( + ( + getattr(xmlsec.constants, name) + for name in dir(xmlsec.constants) + if type(getattr(xmlsec.constants, name)).__name__ == typename + ), + key=lambda t: t.name.lower(), + ) + ) + + +@given(transform=strategies.sampled_from(_constants('__Transform'))) +def test_transform_str(transform): + """Test string representation of ``xmlsec.constants.__Transform``.""" + assert str(transform) == '{}, {}'.format(transform.name, transform.href) + + +@given(transform=strategies.sampled_from(_constants('__Transform'))) +def test_transform_repr(transform): + """Test raw string representation of ``xmlsec.constants.__Transform``.""" + assert repr(transform) == '__Transform({!r}, {!r}, {})'.format(transform.name, transform.href, transform.usage) + + +@given(keydata=strategies.sampled_from(_constants('__KeyData'))) +def test_keydata_str(keydata): + """Test string representation of ``xmlsec.constants.__KeyData``.""" + assert str(keydata) == '{}, {}'.format(keydata.name, keydata.href) + + +@given(keydata=strategies.sampled_from(_constants('__KeyData'))) +def test_keydata_repr(keydata): + """Test raw string representation of ``xmlsec.constants.__KeyData``.""" + assert repr(keydata) == '__KeyData({!r}, {!r})'.format(keydata.name, keydata.href) From b34c0ec0d8f1421a20c46a814d8a9acb31b664b5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:21:39 +0200 Subject: [PATCH 093/378] add hypothesis to test requirements Signed-off-by: oleg.hoefling --- requirements-test.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/requirements-test.txt b/requirements-test.txt index 7c3bc70f..dde7de3d 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,2 +1,3 @@ -r requirements.txt pytest>=4.6.9 +hypothesis From 812a114a23ef15894b1aeae36cf1f8a6756267e4 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:26:43 +0200 Subject: [PATCH 094/378] implement repr methods for __Transform and __KeyData classes, fix segfault for missing href attribute Some constants are missing `href`, see e.g. [xmlSecTransformRemoveXmlTagsC14NKlass](https://github.com/lsh123/xmlsec/blob/cd6fe1c19bd40e0e3bd63af61c34d595371e2bc9/src/c14n.c#L697). Access to `href` thus ends in a segfault in Python: ``` import xmlsec print(xmlsec.constants.TransformRemoveXmlTagsC14N.href) ``` This PR fixes that by returning `None` to avoid a null pointer. Signed-off-by: oleg.hoefling --- src/constants.c | 47 ++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 40 insertions(+), 7 deletions(-) diff --git a/src/constants.c b/src/constants.c index a23dfb78..e5947d1c 100644 --- a/src/constants.c +++ b/src/constants.c @@ -22,7 +22,22 @@ static void PyXmlSec_Transform__del__(PyObject* self) { static PyObject* PyXmlSec_Transform__str__(PyObject* self) { char buf[300]; PyXmlSec_Transform* transform = (PyXmlSec_Transform*)(self); - snprintf(buf, sizeof(buf), "%s, %s", transform->id->name, transform->id->href); + if (transform->id->href != NULL) + snprintf(buf, sizeof(buf), "%s, %s", transform->id->name, transform->id->href); + else + snprintf(buf, sizeof(buf), "%s, None", transform->id->name); + + return PyString_FromString(buf); +} + +// __repr__ method +static PyObject* PyXmlSec_Transform__repr__(PyObject* self) { + char buf[300]; + PyXmlSec_Transform* transform = (PyXmlSec_Transform*)(self); + if (transform->id->href != NULL) + snprintf(buf, sizeof(buf), "__Transform('%s', '%s', %d)", transform->id->name, transform->id->href, transform->id->usage); + else + snprintf(buf, sizeof(buf), "__Transform('%s', None, %d)", transform->id->name, transform->id->usage); return PyString_FromString(buf); } @@ -33,7 +48,9 @@ static PyObject* PyXmlSec_TransformNameGet(PyXmlSec_Transform* self, void* closu static const char PyXmlSec_TransformHrefGet__doc__[] = "The transform's identification string (href)."; static PyObject* PyXmlSec_TransformHrefGet(PyXmlSec_Transform* self, void* closure) { - return PyString_FromString((const char*)self->id->href); + if (self->id->href != NULL) + return PyString_FromString((const char*)self->id->href); + Py_RETURN_NONE; } static const char PyXmlSec_TransformUsageGet__doc__[] = "The allowed transforms usages."; @@ -76,7 +93,7 @@ static PyTypeObject _PyXmlSec_TransformType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + PyXmlSec_Transform__repr__, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -128,7 +145,21 @@ static void PyXmlSec_KeyData__del__(PyObject* self) { static PyObject* PyXmlSec_KeyData__str__(PyObject* self) { char buf[300]; PyXmlSec_KeyData* keydata = (PyXmlSec_KeyData*)(self); - snprintf(buf, sizeof(buf), "%s, %s", keydata->id->name, keydata->id->href); + if (keydata->id->href != NULL) + snprintf(buf, sizeof(buf), "%s, %s", keydata->id->name, keydata->id->href); + else + snprintf(buf, sizeof(buf), "%s, None", keydata->id->name); + return PyString_FromString(buf); +} + +// __repr__ method +static PyObject* PyXmlSec_KeyData__repr__(PyObject* self) { + char buf[300]; + PyXmlSec_KeyData* keydata = (PyXmlSec_KeyData*)(self); + if (keydata->id->href != NULL) + snprintf(buf, sizeof(buf), "__KeyData('%s', '%s')", keydata->id->name, keydata->id->href); + else + snprintf(buf, sizeof(buf), "__KeyData('%s', None)", keydata->id->name); return PyString_FromString(buf); } @@ -139,7 +170,9 @@ static PyObject* PyXmlSec_KeyDataNameGet(PyXmlSec_KeyData* self, void* closure) static const char PyXmlSec_KeyDataHrefGet__doc__[] = "The key data's identification string (href)."; static PyObject* PyXmlSec_KeyDataHrefGet(PyXmlSec_KeyData* self, void* closure) { - return PyString_FromString((const char*)self->id->href); + if (self->id->href != NULL) + return PyString_FromString((const char*)self->id->href); + Py_RETURN_NONE; } static PyGetSetDef PyXmlSec_KeyDataGetSet[] = { @@ -170,7 +203,7 @@ static PyTypeObject _PyXmlSec_KeyDataType = { 0, /* tp_getattr */ 0, /* tp_setattr */ 0, /* tp_reserved */ - 0, /* tp_repr */ + PyXmlSec_KeyData__repr__, /* tp_repr */ 0, /* tp_as_number */ 0, /* tp_as_sequence */ 0, /* tp_as_mapping */ @@ -394,7 +427,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePublic, "PUBLIC"); PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePrivate, "PRIVATE"); PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeSymmetric, "SYMMETRIC"); - PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeSession, "SESSION");; + PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeSession, "SESSION"); PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypePermanent, "PERMANENT"); PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeTrusted, "TRUSTED"); PYXMLSEC_ADD_KEY_TYPE_CONSTANT(KeyDataTypeAny, "ANY"); From 3a6d65d39e8a7dde7a8e5d7db9a104e4af394b3f Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 13:24:18 +0200 Subject: [PATCH 095/378] use --upgrade --force-reinstall as travis venv has preinstalled packages of incompatible versions and pip struggles to resolve the conflicts Signed-off-by: oleg.hoefling --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index f119af4e..3c87d2be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -34,7 +34,8 @@ addons: - pkg-config - lcov install: -- travis_retry pip install coverage codecov -r requirements-test.txt +- travis_retry pip install --upgrade pip setuptools wheel +- travis_retry pip install coverage codecov -r requirements-test.txt --upgrade --force-reinstall - travis_retry pip install -e "." - pip list script: coverage run -m pytest -v tests From a5eb3f0b43c9ee7a2f0f18801e0cfb7a3bd09931 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 10 May 2020 13:56:01 +0200 Subject: [PATCH 096/378] fix spelling in message on keysmanager init error Signed-off-by: oleg.hoefling --- src/keys.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/keys.c b/src/keys.c index 01d7fa30..1b660d25 100644 --- a/src/keys.c +++ b/src/keys.c @@ -562,12 +562,12 @@ static int PyXmlSec_KeysManager__init__(PyObject* self, PyObject* args, PyObject PYXMLSEC_DEBUGF("%p: init key manager", self); if (handle == NULL) { - PyXmlSec_SetLastError("failed to create xmlsecKeyManger"); + PyXmlSec_SetLastError("failed to create xmlsecKeyManager"); return -1; } if (xmlSecCryptoAppDefaultKeysMngrInit(handle) < 0) { xmlSecKeysMngrDestroy(handle); - PyXmlSec_SetLastError("failed to initialize xmlsecKeyManger"); + PyXmlSec_SetLastError("failed to initialize xmlsecKeyManager"); return -1; } PYXMLSEC_DEBUGF("%p: init key manager - done: %p", self, handle); From 718fe7c0ead7a3ffcc16974e5e448498033abd3a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 00:21:51 +0200 Subject: [PATCH 097/378] build static lib on windows and linux Signed-off-by: oleg.hoefling --- build.py | 381 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 381 insertions(+) create mode 100644 build.py diff --git a/build.py b/build.py new file mode 100644 index 00000000..84c55795 --- /dev/null +++ b/build.py @@ -0,0 +1,381 @@ +import multiprocessing +import os +import subprocess +import sys +import tarfile +import zipfile +from distutils import log + +from setuptools import Extension, setup +from setuptools.command.build_ext import build_ext as build_ext_orig + +if sys.version_info >= (3, 4): + from pathlib import Path + from urllib.request import urlcleanup, urljoin, urlretrieve +else: + from urllib import urlcleanup, urljoin, urlretrieve + from pathlib2 import Path + + +class build_ext(build_ext_orig): + def info(self, message): + self.announce(message, level=log.INFO) + + def run(self): + if os.environ.get('STATIC_DEPS', False) or sys.platform == 'win32': + self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) + buildroot = Path('build', 'tmp') + + self.prefix_dir = buildroot / 'prefix' + self.prefix_dir.mkdir(parents=True, exist_ok=True) + self.prefix_dir = self.prefix_dir.absolute() + + self.build_libs_dir = buildroot / 'libs' + self.build_libs_dir.mkdir(exist_ok=True) + + self.libs_dir = Path(os.environ.get('LIBS_DIR', 'libs')) + self.libs_dir.mkdir(exist_ok=True) + + if sys.platform == 'win32': + self.prepare_static_build_win() + elif 'linux' in sys.platform: + self.prepare_static_build_linux() + super(build_ext, self).run() + + def prepare_static_build_win(self): + release_url = 'https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/' + if sys.version_info < (3, 5): + if sys.maxsize > 2147483647: + suffix = 'vs2008.win64' + else: + suffix = "vs2008.win32" + else: + if sys.maxsize > 2147483647: + suffix = "win64" + else: + suffix = "win32" + + libs = { + 'libxml2': 'libxml2-2.9.4.{}.zip'.format(suffix), + 'libxslt': 'libxslt-1.1.29.{}.zip'.format(suffix), + 'zlib': 'zlib-1.2.8.{}.zip'.format(suffix), + 'iconv': 'iconv-1.14.{}.zip'.format(suffix), + 'openssl': 'openssl-1.0.1.{}.zip'.format(suffix), + 'xmlsec': 'xmlsec-1.2.24.{}.zip'.format(suffix), + } + + for lib, file in libs.items(): + url = urljoin(release_url, file) + destfile = self.libs_dir / file + if destfile.is_file(): + self.info('Using local copy of "{}"'.format(url)) + else: + self.info('Retrieving "{}" to "{}"'.format(url, destfile)) + urlcleanup() # work around FTP bug 27973 in Py2.7.12+ + urlretrieve(url, destfile) + + for p in self.libs_dir.glob('*.zip'): + with zipfile.ZipFile(p) as f: + destdir = self.build_libs_dir + f.extractall(path=destdir) + + ext = self.ext_map['xmlsec'] + ext.define_macros = [ + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('__XMLSEC_FUNCTION__', '__FUNCTION__'), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', '1'), + ('XMLSEC_STATIC', '1'), + ('inline', '__inline'), + ] + ext.libraries = [ + 'libxmlsec_a', + 'libxmlsec-openssl_a', + 'libeay32', + 'iconv_a', + 'libxslt_a', + 'libexslt_a', + 'libxml2_a', + 'zlib', + 'WS2_32', + 'Advapi32', + 'User32', + 'Gdi32', + 'Crypt32', + ] + + includes = [p for p in self.build_libs_dir.rglob('include') if p.is_dir()] + includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) + ext.include_dirs = [str(p.absolute()) for p in includes] + ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] + + def prepare_static_build_linux(self): + self.debug = os.environ.get('DEBUG', False) + self.openssl_version = '1.1.1g' + self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') + self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) + self.libxslt_version = os.environ.get('LIBXLST_VERSION', None) + self.zlib_version = os.environ.get('ZLIB_VERSION', '1.2.11') + self.xmlsec1_version = os.environ.get('XMLSEC1_VERSION', '1.2.30') + + self.info('Settings:') + self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) + self.info('{:20} {}'.format('zlib version:', self.zlib_version)) + self.info('{:20} {}'.format('libiconv version:', self.libiconv_version)) + self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version)) + self.info('{:20} {}'.format('libxslt version:', self.libxslt_version)) + self.info('{:20} {}'.format('xmlsec1 version:', self.xmlsec1_version)) + + # fetch openssl + openssl_tar = next(self.libs_dir.glob('openssl*.tar.gz'), None) + if openssl_tar is None: + self.info('OpenSSL source tar not found, downloading ...') + openssl_tar = self.libs_dir / 'openssl.tar.gz' + urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), openssl_tar) + + # fetch zlib + zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) + if zlib_tar is None: + self.info('zlib source tar not found, downloading ...') + zlib_tar = self.libs_dir / 'zlib.tar.gz' + urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), zlib_tar) + + # fetch libiconv + libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) + if libiconv_tar is None: + self.info('libiconv source tar not found, downloading ...') + libiconv_tar = self.libs_dir / 'libiconv.tar.gz' + urlretrieve('https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), libiconv_tar) + + # fetch libxml2 + libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.gz'), None) + if libxml2_tar is None: + self.info('Libxml2 source tar not found, downloading ...') + if self.libxml2_version is None: + url = 'http://xmlsoft.org/sources/LATEST_LIBXML2' + else: + url = 'http://xmlsoft.org/sources/libxml2-{}.tar.gz'.format(self.libxml2_version) + libxml2_tar = self.libs_dir / 'libxml2.tar.gz' + urlretrieve(url, libxml2_tar) + + # fetch libxslt + libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) + if libxslt_tar is None: + self.info('libxslt source tar not found, downloading ...') + if self.libxslt_version is None: + url = 'http://xmlsoft.org/sources/LATEST_LIBXSLT' + else: + url = 'http://xmlsoft.org/sources/libxslt-{}.tar.gz'.format(self.libxslt_version) + libxslt_tar = self.libs_dir / 'libxslt.tar.gz' + urlretrieve(url, libxslt_tar) + + # fetch xmlsec1 + xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) + if xmlsec1_tar is None: + self.info('xmlsec1 source tar not found, downloading ...') + url = 'http://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' + urlretrieve(url, xmlsec1_tar) + + for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): + self.info('Unpacking {}'.format(file.name)) + with tarfile.open(file) as tar: + tar.extractall(path=self.build_libs_dir) + + prefix_arg = '--prefix={}'.format(prefix_dir) + + cflags = ['-fPIC'] + env = os.environ.copy() + if 'CFLAGS' in env: + env['CFLAGS'].append(' '.join(cflags)) + else: + env['CFLAGS'] = ' '.join(cflags) + + self.info('Building OpenSSL') + openssl_dir = next(self.build_libs_dir.glob('openssl-*')) + subprocess.run(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=openssl_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=openssl_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=openssl_dir, env=env) + + self.info('Building zlib') + zlib_dir = next(self.build_libs_dir.glob('zlib-*')) + subprocess.run(['./configure', prefix_arg], cwd=zlib_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=zlib_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=zlib_dir, env=env) + + self.info('Building libiconv') + libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) + subprocess.run( + ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=libiconv_dir, env=env + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libiconv_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libiconv_dir, env=env) + + self.info('Building LibXML2') + libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--without-python', + '--with-iconv={}'.format(self.prefix_dir), + '--with-zlib={}'.format(self.prefix_dir), + ], + cwd=libxml2_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxml2_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxml2_dir, env=env) + + self.info('Building libxslt') + libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--without-python', + '--with-libxml-prefix={}'.format(self.prefix_dir), + '--without-crypto', + ], + cwd=libxslt_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxslt_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxslt_dir, env=env) + + self.info('Building xmlsec1') + if 'LDFLAGS' in env: + env['LDFLAGS'].append(' -lpthread') + else: + env['LDFLAGS'] = '-lpthread' + xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--disable-shared', + '--disable-gost', + '--disable-crypto-dl', + '--enable-static=yes', + '--enable-shared=no', + '--enable-static-linking=yes', + '--with-default-crypto=openssl', + '--with-openssl={}'.format(self.prefix_dir), + '--with-libxml={}'.format(self.prefix_dir), + '--with-libxslt={}'.format(self.prefix_dir), + ], + cwd=xmlsec1_dir, + env=env, + ) + subprocess.run( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] + + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], + cwd=xmlsec1_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=xmlsec1_dir, env=env) + + ext = self.ext_map['xmlsec'] + ext.define_macros = [ + ('MODULE_NAME', self.distribution.metadata.name), + ('MODULE_VERSION', self.distribution.metadata.version), + ('__XMLSEC_FUNCTION__', '__func__'), + ('XMLSEC_NO_SIZE_T', None), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_GOST2012', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', '1'), + ('XMLSEC_STATIC', '1'), + ('inline', '__inline'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ] + + if self.debug: + ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) + + ext.extra_compile_args.extend( + [ + '-O0', + '-g', + '-std=c99', + '-fPIC', + '-fno-strict-aliasing', + '-Wno-error=declaration-after-statement', + '-Werror=implicit-function-declaration', + ] + ) + + ext.include_dirs.append(str(self.prefix_dir / 'include')) + ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) + import lxml + + ext.include_dirs.extend(lxml.get_include()) + + ext.library_dirs = [] + ext.libraries = ['m', 'rt'] + extra_objects = [ + 'libxmlsec1.a', + 'libxslt.a', + 'libxml2.a', + 'libz.a', + 'libxmlsec1-openssl.a', + 'libcrypto.a', + 'libiconv.a', + 'libxmlsec1.a', + ] + ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] + + +src_root = Path('src') +sources = [str(p.absolute()) for p in src_root.rglob('*.c')] +pyxmlsec = Extension('xmlsec', sources=sources) +setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig', 'lxml>=3.8'] + +if sys.version_info < (3,): + setup_reqs.append('pathlib2') + + +setup( + name='xmlsec', + use_scm_version=True, + description='Python bindings for the XML Security Library', + ext_modules=[pyxmlsec], + cmdclass={'build_ext': build_ext}, + setup_requires=setup_reqs, + install_requires=['lxml>=3.8'], + author="Bulat Gaifullin", + author_email='support@mehcode.com', + maintainer='Oleg Hoefling', + maintainer_email='oleg.hoefling@gmail.com', + url='https://github.com/mehcode/python-xmlsec', + license='MIT', + keywords=['xmlsec'], + classifiers=[ + 'Development Status :: 5 - Production/Stable', + 'Intended Audience :: Developers', + 'Intended Audience :: System Administrators', + 'License :: OSI Approved :: MIT License', + 'Operating System :: OS Independent', + 'Programming Language :: C', + 'Programming Language :: Python :: 2.7', + 'Programming Language :: Python :: 3', + 'Programming Language :: Python :: 3.5', + 'Programming Language :: Python :: 3.6', + 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', + 'Topic :: Text Processing :: Markup :: XML', + ], +) From 20e0e1c6d780186613cbc87f2ff1c59a7e37cdc1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 18:27:35 +0200 Subject: [PATCH 098/378] add lxml include dirs on windows static build Signed-off-by: oleg.hoefling --- build.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/build.py b/build.py index 84c55795..e63e5e03 100644 --- a/build.py +++ b/build.py @@ -110,11 +110,15 @@ def prepare_static_build_win(self): 'Gdi32', 'Crypt32', ] + ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] includes = [p for p in self.build_libs_dir.rglob('include') if p.is_dir()] includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) ext.include_dirs = [str(p.absolute()) for p in includes] - ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] + + import lxml + + ext.include_dirs.extend(lxml.get_include()) def prepare_static_build_linux(self): self.debug = os.environ.get('DEBUG', False) From 1e023faaeee5ee958fd883a97f93678d92a5118b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 19:08:07 +0200 Subject: [PATCH 099/378] add windows specific and debug flags Signed-off-by: oleg.hoefling --- build.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/build.py b/build.py index e63e5e03..b495b326 100644 --- a/build.py +++ b/build.py @@ -22,6 +22,7 @@ def info(self, message): self.announce(message, level=log.INFO) def run(self): + self.debug = os.environ.get('DEBUG', False) if os.environ.get('STATIC_DEPS', False) or sys.platform == 'win32': self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) buildroot = Path('build', 'tmp') @@ -40,6 +41,14 @@ def run(self): self.prepare_static_build_win() elif 'linux' in sys.platform: self.prepare_static_build_linux() + + ext = self.ext_map['xmlsec'] + if self.debug: + ext.extra_compile_args.append('-Wall') + ext.extra_compile_args.append('-O0') + else: + ext.extra_compile_args.append('-Os') + super(build_ext, self).run() def prepare_static_build_win(self): @@ -81,6 +90,8 @@ def prepare_static_build_win(self): ext = self.ext_map['xmlsec'] ext.define_macros = [ + ('MODULE_NAME', self.distribution.metadata.name), + ('MODULE_VERSION', self.distribution.metadata.version), ('XMLSEC_CRYPTO', '\\"openssl\\"'), ('__XMLSEC_FUNCTION__', '__FUNCTION__'), ('XMLSEC_NO_GOST', '1'), @@ -120,8 +131,9 @@ def prepare_static_build_win(self): ext.include_dirs.extend(lxml.get_include()) + ext.extra_compile_args.append('/Zi') + def prepare_static_build_linux(self): - self.debug = os.environ.get('DEBUG', False) self.openssl_version = '1.1.1g' self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) From 3b4fdb3717710aea299b9818d2107193d936cd3b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 2 May 2020 14:38:29 +0200 Subject: [PATCH 100/378] declare local vars at the beginning of the function body to fix python 2.7 builds Signed-off-by: oleg.hoefling --- src/enc.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/enc.c b/src/enc.c index 9db0b1b8..199e94a6 100644 --- a/src/enc.c +++ b/src/enc.c @@ -169,6 +169,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec // release the replaced nodes in a way safe for `lxml` static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocumentPtr doc) { + PyXmlSec_LxmlElementPtr* elem; // release the replaced nodes in a way safe for `lxml` xmlNodePtr n = ctx->replacedNodeList; xmlNodePtr nn; @@ -177,7 +178,7 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; // if n has references, it will not be deleted - PyXmlSec_LxmlElementPtr* elem = PyXmlSec_elementFactory(doc, n); + elem = PyXmlSec_elementFactory(doc, n); if (NULL == elem) xmlFreeNode(n); else From 8113669715a19966d1e2fb59d10d660029fc08a6 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 19:40:09 +0200 Subject: [PATCH 101/378] add 3.8 win builds on appveyor Signed-off-by: oleg.hoefling --- .appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index a9a7cde2..6945d269 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,6 +10,8 @@ environment: - python: 36-x64 - python: 37 - python: 37-x64 + - python: 38 + - python: 38-x64 install: - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% From 29309ba950862fb807d891dd9ab31e8729f6297f Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 21:24:24 +0200 Subject: [PATCH 102/378] move common config to top Signed-off-by: oleg.hoefling --- build.py | 111 +++++++++++++++++++++++++++++++------------------------ 1 file changed, 62 insertions(+), 49 deletions(-) diff --git a/build.py b/build.py index b495b326..86d19ea1 100644 --- a/build.py +++ b/build.py @@ -5,6 +5,7 @@ import tarfile import zipfile from distutils import log +from distutils.errors import DistutilsError from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig @@ -22,8 +23,11 @@ def info(self, message): self.announce(message, level=log.INFO) def run(self): + ext = self.ext_map['xmlsec'] self.debug = os.environ.get('DEBUG', False) - if os.environ.get('STATIC_DEPS', False) or sys.platform == 'win32': + self.static = os.environ.get('STATIC_DEPS', False) + + if self.static or sys.platform == 'win32': self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) buildroot = Path('build', 'tmp') @@ -41,13 +45,50 @@ def run(self): self.prepare_static_build_win() elif 'linux' in sys.platform: self.prepare_static_build_linux() + else: + import pkgconfig - ext = self.ext_map['xmlsec'] - if self.debug: - ext.extra_compile_args.append('-Wall') - ext.extra_compile_args.append('-O0') - else: - ext.extra_compile_args.append('-Os') + try: + config = pkgconfig.parse('xmlsec1') + except EnvironmentError: + raise DistutilsError('Unable to invoke pkg-config.') + + if config is None or not config.get('libraries'): + raise DistutilsError('Bad or uncomplete result returned from pkg-config') + + ext.define_macros.extend(config['define_macros']) + ext.include_dirs.extend(config['include_dirs']) + ext.library_dirs.extend(config['library_dirs']) + ext.libraries.extend(config['libraries']) + + import lxml + + ext.include_dirs.extend(lxml.get_include()) + + ext.define_macros.extend( + [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] + ) + + if sys.platform == 'win32': + ext.extra_compile_args.append('/Zi') + else: + ext.extra_compile_args.extend( + [ + '-g', + '-std=c99', + '-fPIC', + '-fno-strict-aliasing', + '-Wno-error=declaration-after-statement', + '-Werror=implicit-function-declaration', + ] + ) + + if self.debug: + ext.extra_compile_args.append('-Wall') + ext.extra_compile_args.append('-O0') + ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) + else: + ext.extra_compile_args.append('-Os') super(build_ext, self).run() @@ -64,18 +105,18 @@ def prepare_static_build_win(self): else: suffix = "win32" - libs = { - 'libxml2': 'libxml2-2.9.4.{}.zip'.format(suffix), - 'libxslt': 'libxslt-1.1.29.{}.zip'.format(suffix), - 'zlib': 'zlib-1.2.8.{}.zip'.format(suffix), - 'iconv': 'iconv-1.14.{}.zip'.format(suffix), - 'openssl': 'openssl-1.0.1.{}.zip'.format(suffix), - 'xmlsec': 'xmlsec-1.2.24.{}.zip'.format(suffix), - } - - for lib, file in libs.items(): - url = urljoin(release_url, file) - destfile = self.libs_dir / file + libs = [ + 'libxml2-2.9.4.{}.zip'.format(suffix), + 'libxslt-1.1.29.{}.zip'.format(suffix), + 'zlib-1.2.8.{}.zip'.format(suffix), + 'iconv-1.14.{}.zip'.format(suffix), + 'openssl-1.0.1.{}.zip'.format(suffix), + 'xmlsec-1.2.24.{}.zip'.format(suffix), + ] + + for libfile in libs: + url = urljoin(release_url, libfile) + destfile = self.libs_dir / libfile if destfile.is_file(): self.info('Using local copy of "{}"'.format(url)) else: @@ -90,8 +131,6 @@ def prepare_static_build_win(self): ext = self.ext_map['xmlsec'] ext.define_macros = [ - ('MODULE_NAME', self.distribution.metadata.name), - ('MODULE_VERSION', self.distribution.metadata.version), ('XMLSEC_CRYPTO', '\\"openssl\\"'), ('__XMLSEC_FUNCTION__', '__FUNCTION__'), ('XMLSEC_NO_GOST', '1'), @@ -127,14 +166,8 @@ def prepare_static_build_win(self): includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) ext.include_dirs = [str(p.absolute()) for p in includes] - import lxml - - ext.include_dirs.extend(lxml.get_include()) - - ext.extra_compile_args.append('/Zi') - def prepare_static_build_linux(self): - self.openssl_version = '1.1.1g' + self.openssl_version = os.environ.get('OPENSSL_VERSION', '1.1.1g') self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) self.libxslt_version = os.environ.get('LIBXLST_VERSION', None) @@ -205,7 +238,7 @@ def prepare_static_build_linux(self): with tarfile.open(file) as tar: tar.extractall(path=self.build_libs_dir) - prefix_arg = '--prefix={}'.format(prefix_dir) + prefix_arg = '--prefix={}'.format(self.prefix_dir) cflags = ['-fPIC'] env = os.environ.copy() @@ -300,8 +333,6 @@ def prepare_static_build_linux(self): ext = self.ext_map['xmlsec'] ext.define_macros = [ - ('MODULE_NAME', self.distribution.metadata.name), - ('MODULE_VERSION', self.distribution.metadata.version), ('__XMLSEC_FUNCTION__', '__func__'), ('XMLSEC_NO_SIZE_T', None), ('XMLSEC_NO_GOST', '1'), @@ -319,26 +350,8 @@ def prepare_static_build_linux(self): ('_UNICODE', '1'), ] - if self.debug: - ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) - - ext.extra_compile_args.extend( - [ - '-O0', - '-g', - '-std=c99', - '-fPIC', - '-fno-strict-aliasing', - '-Wno-error=declaration-after-statement', - '-Werror=implicit-function-declaration', - ] - ) - ext.include_dirs.append(str(self.prefix_dir / 'include')) ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) - import lxml - - ext.include_dirs.extend(lxml.get_include()) ext.library_dirs = [] ext.libraries = ['m', 'rt'] From b425f70a8254cc19382d7f40905e98aa68f6b2ba Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:18:32 +0200 Subject: [PATCH 103/378] handle pkgconfig missing package and tar extraction errors Signed-off-by: oleg.hoefling --- build.py | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/build.py b/build.py index 86d19ea1..8a914f46 100644 --- a/build.py +++ b/build.py @@ -52,9 +52,11 @@ def run(self): config = pkgconfig.parse('xmlsec1') except EnvironmentError: raise DistutilsError('Unable to invoke pkg-config.') + except pkgconfig.PackageNotFoundError: + raise DistutilsError('xmlsec1 is not installed or not in path.') if config is None or not config.get('libraries'): - raise DistutilsError('Bad or uncomplete result returned from pkg-config') + raise DistutilsError('Bad or uncomplete result returned from pkg-config.') ext.define_macros.extend(config['define_macros']) ext.include_dirs.extend(config['include_dirs']) @@ -178,8 +180,8 @@ def prepare_static_build_linux(self): self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) self.info('{:20} {}'.format('zlib version:', self.zlib_version)) self.info('{:20} {}'.format('libiconv version:', self.libiconv_version)) - self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version)) - self.info('{:20} {}'.format('libxslt version:', self.libxslt_version)) + self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version or 'unset, using latest')) + self.info('{:20} {}'.format('libxslt version:', self.libxslt_version or 'unset, using latest')) self.info('{:20} {}'.format('xmlsec1 version:', self.xmlsec1_version)) # fetch openssl @@ -235,8 +237,11 @@ def prepare_static_build_linux(self): for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): self.info('Unpacking {}'.format(file.name)) - with tarfile.open(file) as tar: - tar.extractall(path=self.build_libs_dir) + try: + with tarfile.open(file) as tar: + tar.extractall(path=self.build_libs_dir) + except EOFError: + raise DistutilsError('Bad {} downloaded; remove it and try again.'.format(file.name)) prefix_arg = '--prefix={}'.format(self.prefix_dir) From b822ba99ee739499a56ba854e415d91340e34517 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:20:31 +0200 Subject: [PATCH 104/378] try new build script on real pipelines Signed-off-by: oleg.hoefling --- build.py | 415 ----------------------------------------------------- setup.py | 425 ++++++++++++++++++++++++++++++++++++++++++++++++++----- 2 files changed, 389 insertions(+), 451 deletions(-) delete mode 100644 build.py diff --git a/build.py b/build.py deleted file mode 100644 index 8a914f46..00000000 --- a/build.py +++ /dev/null @@ -1,415 +0,0 @@ -import multiprocessing -import os -import subprocess -import sys -import tarfile -import zipfile -from distutils import log -from distutils.errors import DistutilsError - -from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext as build_ext_orig - -if sys.version_info >= (3, 4): - from pathlib import Path - from urllib.request import urlcleanup, urljoin, urlretrieve -else: - from urllib import urlcleanup, urljoin, urlretrieve - from pathlib2 import Path - - -class build_ext(build_ext_orig): - def info(self, message): - self.announce(message, level=log.INFO) - - def run(self): - ext = self.ext_map['xmlsec'] - self.debug = os.environ.get('DEBUG', False) - self.static = os.environ.get('STATIC_DEPS', False) - - if self.static or sys.platform == 'win32': - self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) - buildroot = Path('build', 'tmp') - - self.prefix_dir = buildroot / 'prefix' - self.prefix_dir.mkdir(parents=True, exist_ok=True) - self.prefix_dir = self.prefix_dir.absolute() - - self.build_libs_dir = buildroot / 'libs' - self.build_libs_dir.mkdir(exist_ok=True) - - self.libs_dir = Path(os.environ.get('LIBS_DIR', 'libs')) - self.libs_dir.mkdir(exist_ok=True) - - if sys.platform == 'win32': - self.prepare_static_build_win() - elif 'linux' in sys.platform: - self.prepare_static_build_linux() - else: - import pkgconfig - - try: - config = pkgconfig.parse('xmlsec1') - except EnvironmentError: - raise DistutilsError('Unable to invoke pkg-config.') - except pkgconfig.PackageNotFoundError: - raise DistutilsError('xmlsec1 is not installed or not in path.') - - if config is None or not config.get('libraries'): - raise DistutilsError('Bad or uncomplete result returned from pkg-config.') - - ext.define_macros.extend(config['define_macros']) - ext.include_dirs.extend(config['include_dirs']) - ext.library_dirs.extend(config['library_dirs']) - ext.libraries.extend(config['libraries']) - - import lxml - - ext.include_dirs.extend(lxml.get_include()) - - ext.define_macros.extend( - [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] - ) - - if sys.platform == 'win32': - ext.extra_compile_args.append('/Zi') - else: - ext.extra_compile_args.extend( - [ - '-g', - '-std=c99', - '-fPIC', - '-fno-strict-aliasing', - '-Wno-error=declaration-after-statement', - '-Werror=implicit-function-declaration', - ] - ) - - if self.debug: - ext.extra_compile_args.append('-Wall') - ext.extra_compile_args.append('-O0') - ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) - else: - ext.extra_compile_args.append('-Os') - - super(build_ext, self).run() - - def prepare_static_build_win(self): - release_url = 'https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/' - if sys.version_info < (3, 5): - if sys.maxsize > 2147483647: - suffix = 'vs2008.win64' - else: - suffix = "vs2008.win32" - else: - if sys.maxsize > 2147483647: - suffix = "win64" - else: - suffix = "win32" - - libs = [ - 'libxml2-2.9.4.{}.zip'.format(suffix), - 'libxslt-1.1.29.{}.zip'.format(suffix), - 'zlib-1.2.8.{}.zip'.format(suffix), - 'iconv-1.14.{}.zip'.format(suffix), - 'openssl-1.0.1.{}.zip'.format(suffix), - 'xmlsec-1.2.24.{}.zip'.format(suffix), - ] - - for libfile in libs: - url = urljoin(release_url, libfile) - destfile = self.libs_dir / libfile - if destfile.is_file(): - self.info('Using local copy of "{}"'.format(url)) - else: - self.info('Retrieving "{}" to "{}"'.format(url, destfile)) - urlcleanup() # work around FTP bug 27973 in Py2.7.12+ - urlretrieve(url, destfile) - - for p in self.libs_dir.glob('*.zip'): - with zipfile.ZipFile(p) as f: - destdir = self.build_libs_dir - f.extractall(path=destdir) - - ext = self.ext_map['xmlsec'] - ext.define_macros = [ - ('XMLSEC_CRYPTO', '\\"openssl\\"'), - ('__XMLSEC_FUNCTION__', '__FUNCTION__'), - ('XMLSEC_NO_GOST', '1'), - ('XMLSEC_NO_XKMS', '1'), - ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), - ('XMLSEC_CRYPTO_OPENSSL', '1'), - ('UNICODE', '1'), - ('_UNICODE', '1'), - ('LIBXML_ICONV_ENABLED', 1), - ('LIBXML_STATIC', '1'), - ('LIBXSLT_STATIC', '1'), - ('XMLSEC_STATIC', '1'), - ('inline', '__inline'), - ] - ext.libraries = [ - 'libxmlsec_a', - 'libxmlsec-openssl_a', - 'libeay32', - 'iconv_a', - 'libxslt_a', - 'libexslt_a', - 'libxml2_a', - 'zlib', - 'WS2_32', - 'Advapi32', - 'User32', - 'Gdi32', - 'Crypt32', - ] - ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] - - includes = [p for p in self.build_libs_dir.rglob('include') if p.is_dir()] - includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) - ext.include_dirs = [str(p.absolute()) for p in includes] - - def prepare_static_build_linux(self): - self.openssl_version = os.environ.get('OPENSSL_VERSION', '1.1.1g') - self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') - self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) - self.libxslt_version = os.environ.get('LIBXLST_VERSION', None) - self.zlib_version = os.environ.get('ZLIB_VERSION', '1.2.11') - self.xmlsec1_version = os.environ.get('XMLSEC1_VERSION', '1.2.30') - - self.info('Settings:') - self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) - self.info('{:20} {}'.format('zlib version:', self.zlib_version)) - self.info('{:20} {}'.format('libiconv version:', self.libiconv_version)) - self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version or 'unset, using latest')) - self.info('{:20} {}'.format('libxslt version:', self.libxslt_version or 'unset, using latest')) - self.info('{:20} {}'.format('xmlsec1 version:', self.xmlsec1_version)) - - # fetch openssl - openssl_tar = next(self.libs_dir.glob('openssl*.tar.gz'), None) - if openssl_tar is None: - self.info('OpenSSL source tar not found, downloading ...') - openssl_tar = self.libs_dir / 'openssl.tar.gz' - urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), openssl_tar) - - # fetch zlib - zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) - if zlib_tar is None: - self.info('zlib source tar not found, downloading ...') - zlib_tar = self.libs_dir / 'zlib.tar.gz' - urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), zlib_tar) - - # fetch libiconv - libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) - if libiconv_tar is None: - self.info('libiconv source tar not found, downloading ...') - libiconv_tar = self.libs_dir / 'libiconv.tar.gz' - urlretrieve('https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), libiconv_tar) - - # fetch libxml2 - libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.gz'), None) - if libxml2_tar is None: - self.info('Libxml2 source tar not found, downloading ...') - if self.libxml2_version is None: - url = 'http://xmlsoft.org/sources/LATEST_LIBXML2' - else: - url = 'http://xmlsoft.org/sources/libxml2-{}.tar.gz'.format(self.libxml2_version) - libxml2_tar = self.libs_dir / 'libxml2.tar.gz' - urlretrieve(url, libxml2_tar) - - # fetch libxslt - libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) - if libxslt_tar is None: - self.info('libxslt source tar not found, downloading ...') - if self.libxslt_version is None: - url = 'http://xmlsoft.org/sources/LATEST_LIBXSLT' - else: - url = 'http://xmlsoft.org/sources/libxslt-{}.tar.gz'.format(self.libxslt_version) - libxslt_tar = self.libs_dir / 'libxslt.tar.gz' - urlretrieve(url, libxslt_tar) - - # fetch xmlsec1 - xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) - if xmlsec1_tar is None: - self.info('xmlsec1 source tar not found, downloading ...') - url = 'http://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) - xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' - urlretrieve(url, xmlsec1_tar) - - for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): - self.info('Unpacking {}'.format(file.name)) - try: - with tarfile.open(file) as tar: - tar.extractall(path=self.build_libs_dir) - except EOFError: - raise DistutilsError('Bad {} downloaded; remove it and try again.'.format(file.name)) - - prefix_arg = '--prefix={}'.format(self.prefix_dir) - - cflags = ['-fPIC'] - env = os.environ.copy() - if 'CFLAGS' in env: - env['CFLAGS'].append(' '.join(cflags)) - else: - env['CFLAGS'] = ' '.join(cflags) - - self.info('Building OpenSSL') - openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - subprocess.run(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=openssl_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=openssl_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=openssl_dir, env=env) - - self.info('Building zlib') - zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.run(['./configure', prefix_arg], cwd=zlib_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=zlib_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=zlib_dir, env=env) - - self.info('Building libiconv') - libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.run( - ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=libiconv_dir, env=env - ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libiconv_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libiconv_dir, env=env) - - self.info('Building LibXML2') - libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.run( - [ - './configure', - prefix_arg, - '--without-python', - '--with-iconv={}'.format(self.prefix_dir), - '--with-zlib={}'.format(self.prefix_dir), - ], - cwd=libxml2_dir, - env=env, - ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxml2_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxml2_dir, env=env) - - self.info('Building libxslt') - libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.run( - [ - './configure', - prefix_arg, - '--without-python', - '--with-libxml-prefix={}'.format(self.prefix_dir), - '--without-crypto', - ], - cwd=libxslt_dir, - env=env, - ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxslt_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxslt_dir, env=env) - - self.info('Building xmlsec1') - if 'LDFLAGS' in env: - env['LDFLAGS'].append(' -lpthread') - else: - env['LDFLAGS'] = '-lpthread' - xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.run( - [ - './configure', - prefix_arg, - '--disable-shared', - '--disable-gost', - '--disable-crypto-dl', - '--enable-static=yes', - '--enable-shared=no', - '--enable-static-linking=yes', - '--with-default-crypto=openssl', - '--with-openssl={}'.format(self.prefix_dir), - '--with-libxml={}'.format(self.prefix_dir), - '--with-libxslt={}'.format(self.prefix_dir), - ], - cwd=xmlsec1_dir, - env=env, - ) - subprocess.run( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] - + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], - cwd=xmlsec1_dir, - env=env, - ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=xmlsec1_dir, env=env) - - ext = self.ext_map['xmlsec'] - ext.define_macros = [ - ('__XMLSEC_FUNCTION__', '__func__'), - ('XMLSEC_NO_SIZE_T', None), - ('XMLSEC_NO_GOST', '1'), - ('XMLSEC_NO_GOST2012', '1'), - ('XMLSEC_NO_XKMS', '1'), - ('XMLSEC_CRYPTO', '\\"openssl\\"'), - ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), - ('XMLSEC_CRYPTO_OPENSSL', '1'), - ('LIBXML_ICONV_ENABLED', 1), - ('LIBXML_STATIC', '1'), - ('LIBXSLT_STATIC', '1'), - ('XMLSEC_STATIC', '1'), - ('inline', '__inline'), - ('UNICODE', '1'), - ('_UNICODE', '1'), - ] - - ext.include_dirs.append(str(self.prefix_dir / 'include')) - ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) - - ext.library_dirs = [] - ext.libraries = ['m', 'rt'] - extra_objects = [ - 'libxmlsec1.a', - 'libxslt.a', - 'libxml2.a', - 'libz.a', - 'libxmlsec1-openssl.a', - 'libcrypto.a', - 'libiconv.a', - 'libxmlsec1.a', - ] - ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] - - -src_root = Path('src') -sources = [str(p.absolute()) for p in src_root.rglob('*.c')] -pyxmlsec = Extension('xmlsec', sources=sources) -setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig', 'lxml>=3.8'] - -if sys.version_info < (3,): - setup_reqs.append('pathlib2') - - -setup( - name='xmlsec', - use_scm_version=True, - description='Python bindings for the XML Security Library', - ext_modules=[pyxmlsec], - cmdclass={'build_ext': build_ext}, - setup_requires=setup_reqs, - install_requires=['lxml>=3.8'], - author="Bulat Gaifullin", - author_email='support@mehcode.com', - maintainer='Oleg Hoefling', - maintainer_email='oleg.hoefling@gmail.com', - url='https://github.com/mehcode/python-xmlsec', - license='MIT', - keywords=['xmlsec'], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: C', - 'Programming Language :: Python :: 2.7', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', - 'Topic :: Text Processing :: Markup :: XML', - ], -) diff --git a/setup.py b/setup.py index 15f48ecf..8a914f46 100644 --- a/setup.py +++ b/setup.py @@ -1,51 +1,404 @@ +import multiprocessing +import os +import subprocess +import sys +import tarfile +import zipfile +from distutils import log +from distutils.errors import DistutilsError + from setuptools import Extension, setup -from setuptools.command import build_ext +from setuptools.command.build_ext import build_ext as build_ext_orig + +if sys.version_info >= (3, 4): + from pathlib import Path + from urllib.request import urlcleanup, urljoin, urlretrieve +else: + from urllib import urlcleanup, urljoin, urlretrieve + from pathlib2 import Path -import xmlsec_setupinfo +class build_ext(build_ext_orig): + def info(self, message): + self.announce(message, level=log.INFO) -class BuildExt(build_ext.build_ext): def run(self): - # at this moment all setup_requires are installed and we can safety import them - self.patch_options() - build_ext.build_ext.run(self) - - def patch_options(self): - ext = self.ext_map[xmlsec_setupinfo.name()] - ext.define_macros.extend(xmlsec_setupinfo.define_macros()) - ext.include_dirs.extend(xmlsec_setupinfo.include_dirs()) - ext.libraries.extend(xmlsec_setupinfo.libraries()) - ext.library_dirs.extend(xmlsec_setupinfo.library_dirs()) - - -_xmlsec = Extension( - xmlsec_setupinfo.name(), - sources=xmlsec_setupinfo.sources(), - extra_compile_args=xmlsec_setupinfo.cflags(), - libraries=[], - library_dirs=[], - include_dirs=[], - define_macros=[], -) + ext = self.ext_map['xmlsec'] + self.debug = os.environ.get('DEBUG', False) + self.static = os.environ.get('STATIC_DEPS', False) + + if self.static or sys.platform == 'win32': + self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) + buildroot = Path('build', 'tmp') + + self.prefix_dir = buildroot / 'prefix' + self.prefix_dir.mkdir(parents=True, exist_ok=True) + self.prefix_dir = self.prefix_dir.absolute() + + self.build_libs_dir = buildroot / 'libs' + self.build_libs_dir.mkdir(exist_ok=True) + + self.libs_dir = Path(os.environ.get('LIBS_DIR', 'libs')) + self.libs_dir.mkdir(exist_ok=True) + + if sys.platform == 'win32': + self.prepare_static_build_win() + elif 'linux' in sys.platform: + self.prepare_static_build_linux() + else: + import pkgconfig + + try: + config = pkgconfig.parse('xmlsec1') + except EnvironmentError: + raise DistutilsError('Unable to invoke pkg-config.') + except pkgconfig.PackageNotFoundError: + raise DistutilsError('xmlsec1 is not installed or not in path.') + + if config is None or not config.get('libraries'): + raise DistutilsError('Bad or uncomplete result returned from pkg-config.') + + ext.define_macros.extend(config['define_macros']) + ext.include_dirs.extend(config['include_dirs']) + ext.library_dirs.extend(config['library_dirs']) + ext.libraries.extend(config['libraries']) + + import lxml + + ext.include_dirs.extend(lxml.get_include()) + + ext.define_macros.extend( + [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] + ) + + if sys.platform == 'win32': + ext.extra_compile_args.append('/Zi') + else: + ext.extra_compile_args.extend( + [ + '-g', + '-std=c99', + '-fPIC', + '-fno-strict-aliasing', + '-Wno-error=declaration-after-statement', + '-Werror=implicit-function-declaration', + ] + ) + + if self.debug: + ext.extra_compile_args.append('-Wall') + ext.extra_compile_args.append('-O0') + ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) + else: + ext.extra_compile_args.append('-Os') + + super(build_ext, self).run() + + def prepare_static_build_win(self): + release_url = 'https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/' + if sys.version_info < (3, 5): + if sys.maxsize > 2147483647: + suffix = 'vs2008.win64' + else: + suffix = "vs2008.win32" + else: + if sys.maxsize > 2147483647: + suffix = "win64" + else: + suffix = "win32" + + libs = [ + 'libxml2-2.9.4.{}.zip'.format(suffix), + 'libxslt-1.1.29.{}.zip'.format(suffix), + 'zlib-1.2.8.{}.zip'.format(suffix), + 'iconv-1.14.{}.zip'.format(suffix), + 'openssl-1.0.1.{}.zip'.format(suffix), + 'xmlsec-1.2.24.{}.zip'.format(suffix), + ] + + for libfile in libs: + url = urljoin(release_url, libfile) + destfile = self.libs_dir / libfile + if destfile.is_file(): + self.info('Using local copy of "{}"'.format(url)) + else: + self.info('Retrieving "{}" to "{}"'.format(url, destfile)) + urlcleanup() # work around FTP bug 27973 in Py2.7.12+ + urlretrieve(url, destfile) + + for p in self.libs_dir.glob('*.zip'): + with zipfile.ZipFile(p) as f: + destdir = self.build_libs_dir + f.extractall(path=destdir) + + ext = self.ext_map['xmlsec'] + ext.define_macros = [ + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('__XMLSEC_FUNCTION__', '__FUNCTION__'), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', '1'), + ('XMLSEC_STATIC', '1'), + ('inline', '__inline'), + ] + ext.libraries = [ + 'libxmlsec_a', + 'libxmlsec-openssl_a', + 'libeay32', + 'iconv_a', + 'libxslt_a', + 'libexslt_a', + 'libxml2_a', + 'zlib', + 'WS2_32', + 'Advapi32', + 'User32', + 'Gdi32', + 'Crypt32', + ] + ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] + + includes = [p for p in self.build_libs_dir.rglob('include') if p.is_dir()] + includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) + ext.include_dirs = [str(p.absolute()) for p in includes] + + def prepare_static_build_linux(self): + self.openssl_version = os.environ.get('OPENSSL_VERSION', '1.1.1g') + self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') + self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) + self.libxslt_version = os.environ.get('LIBXLST_VERSION', None) + self.zlib_version = os.environ.get('ZLIB_VERSION', '1.2.11') + self.xmlsec1_version = os.environ.get('XMLSEC1_VERSION', '1.2.30') + + self.info('Settings:') + self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) + self.info('{:20} {}'.format('zlib version:', self.zlib_version)) + self.info('{:20} {}'.format('libiconv version:', self.libiconv_version)) + self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version or 'unset, using latest')) + self.info('{:20} {}'.format('libxslt version:', self.libxslt_version or 'unset, using latest')) + self.info('{:20} {}'.format('xmlsec1 version:', self.xmlsec1_version)) + + # fetch openssl + openssl_tar = next(self.libs_dir.glob('openssl*.tar.gz'), None) + if openssl_tar is None: + self.info('OpenSSL source tar not found, downloading ...') + openssl_tar = self.libs_dir / 'openssl.tar.gz' + urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), openssl_tar) + + # fetch zlib + zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) + if zlib_tar is None: + self.info('zlib source tar not found, downloading ...') + zlib_tar = self.libs_dir / 'zlib.tar.gz' + urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), zlib_tar) + + # fetch libiconv + libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) + if libiconv_tar is None: + self.info('libiconv source tar not found, downloading ...') + libiconv_tar = self.libs_dir / 'libiconv.tar.gz' + urlretrieve('https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), libiconv_tar) + + # fetch libxml2 + libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.gz'), None) + if libxml2_tar is None: + self.info('Libxml2 source tar not found, downloading ...') + if self.libxml2_version is None: + url = 'http://xmlsoft.org/sources/LATEST_LIBXML2' + else: + url = 'http://xmlsoft.org/sources/libxml2-{}.tar.gz'.format(self.libxml2_version) + libxml2_tar = self.libs_dir / 'libxml2.tar.gz' + urlretrieve(url, libxml2_tar) + + # fetch libxslt + libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) + if libxslt_tar is None: + self.info('libxslt source tar not found, downloading ...') + if self.libxslt_version is None: + url = 'http://xmlsoft.org/sources/LATEST_LIBXSLT' + else: + url = 'http://xmlsoft.org/sources/libxslt-{}.tar.gz'.format(self.libxslt_version) + libxslt_tar = self.libs_dir / 'libxslt.tar.gz' + urlretrieve(url, libxslt_tar) + + # fetch xmlsec1 + xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) + if xmlsec1_tar is None: + self.info('xmlsec1 source tar not found, downloading ...') + url = 'http://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' + urlretrieve(url, xmlsec1_tar) + + for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): + self.info('Unpacking {}'.format(file.name)) + try: + with tarfile.open(file) as tar: + tar.extractall(path=self.build_libs_dir) + except EOFError: + raise DistutilsError('Bad {} downloaded; remove it and try again.'.format(file.name)) + + prefix_arg = '--prefix={}'.format(self.prefix_dir) + + cflags = ['-fPIC'] + env = os.environ.copy() + if 'CFLAGS' in env: + env['CFLAGS'].append(' '.join(cflags)) + else: + env['CFLAGS'] = ' '.join(cflags) + + self.info('Building OpenSSL') + openssl_dir = next(self.build_libs_dir.glob('openssl-*')) + subprocess.run(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=openssl_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=openssl_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=openssl_dir, env=env) + + self.info('Building zlib') + zlib_dir = next(self.build_libs_dir.glob('zlib-*')) + subprocess.run(['./configure', prefix_arg], cwd=zlib_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=zlib_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=zlib_dir, env=env) + + self.info('Building libiconv') + libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) + subprocess.run( + ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=libiconv_dir, env=env + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libiconv_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libiconv_dir, env=env) + + self.info('Building LibXML2') + libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--without-python', + '--with-iconv={}'.format(self.prefix_dir), + '--with-zlib={}'.format(self.prefix_dir), + ], + cwd=libxml2_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxml2_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxml2_dir, env=env) + + self.info('Building libxslt') + libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--without-python', + '--with-libxml-prefix={}'.format(self.prefix_dir), + '--without-crypto', + ], + cwd=libxslt_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxslt_dir, env=env) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxslt_dir, env=env) + + self.info('Building xmlsec1') + if 'LDFLAGS' in env: + env['LDFLAGS'].append(' -lpthread') + else: + env['LDFLAGS'] = '-lpthread' + xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) + subprocess.run( + [ + './configure', + prefix_arg, + '--disable-shared', + '--disable-gost', + '--disable-crypto-dl', + '--enable-static=yes', + '--enable-shared=no', + '--enable-static-linking=yes', + '--with-default-crypto=openssl', + '--with-openssl={}'.format(self.prefix_dir), + '--with-libxml={}'.format(self.prefix_dir), + '--with-libxslt={}'.format(self.prefix_dir), + ], + cwd=xmlsec1_dir, + env=env, + ) + subprocess.run( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] + + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], + cwd=xmlsec1_dir, + env=env, + ) + subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=xmlsec1_dir, env=env) + + ext = self.ext_map['xmlsec'] + ext.define_macros = [ + ('__XMLSEC_FUNCTION__', '__func__'), + ('XMLSEC_NO_SIZE_T', None), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_GOST2012', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', '1'), + ('XMLSEC_STATIC', '1'), + ('inline', '__inline'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ] + + ext.include_dirs.append(str(self.prefix_dir / 'include')) + ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) + + ext.library_dirs = [] + ext.libraries = ['m', 'rt'] + extra_objects = [ + 'libxmlsec1.a', + 'libxslt.a', + 'libxml2.a', + 'libz.a', + 'libxmlsec1-openssl.a', + 'libcrypto.a', + 'libiconv.a', + 'libxmlsec1.a', + ] + ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] + + +src_root = Path('src') +sources = [str(p.absolute()) for p in src_root.rglob('*.c')] +pyxmlsec = Extension('xmlsec', sources=sources) +setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig', 'lxml>=3.8'] + +if sys.version_info < (3,): + setup_reqs.append('pathlib2') + setup( - name=xmlsec_setupinfo.name(), + name='xmlsec', use_scm_version=True, - description=xmlsec_setupinfo.description(), - ext_modules=[_xmlsec], - cmdclass={'build_ext': BuildExt}, - setup_requires=xmlsec_setupinfo.requirements() + ['setuptools_scm[toml]>=3.4'], - install_requires=xmlsec_setupinfo.requirements(), + description='Python bindings for the XML Security Library', + ext_modules=[pyxmlsec], + cmdclass={'build_ext': build_ext}, + setup_requires=setup_reqs, + install_requires=['lxml>=3.8'], author="Bulat Gaifullin", author_email='support@mehcode.com', - maintainer='Bulat Gaifullin', - maintainer_email='gaifullinbf@gmail.com', + maintainer='Oleg Hoefling', + maintainer_email='oleg.hoefling@gmail.com', url='https://github.com/mehcode/python-xmlsec', - download_url="https://github.com/mehcode/python-xmlsec/archive/v%s.tar.gz" % xmlsec_setupinfo.version(), license='MIT', - keywords=["xmlsec"], + keywords=['xmlsec'], classifiers=[ - xmlsec_setupinfo.dev_status(), + 'Development Status :: 5 - Production/Stable', 'Intended Audience :: Developers', 'Intended Audience :: System Administrators', 'License :: OSI Approved :: MIT License', @@ -53,10 +406,10 @@ def patch_options(self): 'Programming Language :: C', 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.4', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', + 'Programming Language :: Python :: 3.8', 'Topic :: Text Processing :: Markup :: XML', ], ) From aaba1ae5a0d93fc7a3a89e6c6efa922726f78b8c Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:22:47 +0200 Subject: [PATCH 105/378] fix urljoin import on python 2 Signed-off-by: oleg.hoefling --- setup.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 8a914f46..ac71939e 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,8 @@ from pathlib import Path from urllib.request import urlcleanup, urljoin, urlretrieve else: - from urllib import urlcleanup, urljoin, urlretrieve + from urllib import urlcleanup, urlretrieve + from urlparse import urljoin from pathlib2 import Path From ab5c884f29063737fdce24589542d77161008e13 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:49:33 +0200 Subject: [PATCH 106/378] more python 2 compat Signed-off-by: oleg.hoefling --- setup.py | 82 +++++++++++++++++++++++++++++++++++--------------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/setup.py b/setup.py index ac71939e..74ced1a2 100644 --- a/setup.py +++ b/setup.py @@ -16,14 +16,16 @@ else: from urllib import urlcleanup, urlretrieve from urlparse import urljoin - from pathlib2 import Path -class build_ext(build_ext_orig): +class build_ext(build_ext_orig, object): def info(self, message): self.announce(message, level=log.INFO) def run(self): + if sys.version_info < (3, 4): + from pathlib2 import Path + ext = self.ext_map['xmlsec'] self.debug = os.environ.get('DEBUG', False) self.static = os.environ.get('STATIC_DEPS', False) @@ -239,8 +241,8 @@ def prepare_static_build_linux(self): for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): self.info('Unpacking {}'.format(file.name)) try: - with tarfile.open(file) as tar: - tar.extractall(path=self.build_libs_dir) + with tarfile.open(str(file)) as tar: + tar.extractall(path=str(self.build_libs_dir)) except EOFError: raise DistutilsError('Bad {} downloaded; remove it and try again.'.format(file.name)) @@ -255,27 +257,31 @@ def prepare_static_build_linux(self): self.info('Building OpenSSL') openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - subprocess.run(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=openssl_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=openssl_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=openssl_dir, env=env) + subprocess.check_output(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=str(openssl_dir), env=env) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) + subprocess.check_output( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env + ) self.info('Building zlib') zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.run(['./configure', prefix_arg], cwd=zlib_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=zlib_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=zlib_dir, env=env) + subprocess.check_output(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.run( - ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=libiconv_dir, env=env + subprocess.check_output( + ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=str(libiconv_dir), env=env + ) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) + subprocess.check_output( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libiconv_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libiconv_dir, env=env) self.info('Building LibXML2') libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.run( + subprocess.check_output( [ './configure', prefix_arg, @@ -283,15 +289,17 @@ def prepare_static_build_linux(self): '--with-iconv={}'.format(self.prefix_dir), '--with-zlib={}'.format(self.prefix_dir), ], - cwd=libxml2_dir, + cwd=str(libxml2_dir), env=env, ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxml2_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxml2_dir, env=env) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) + subprocess.check_output( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env + ) self.info('Building libxslt') libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.run( + subprocess.check_output( [ './configure', prefix_arg, @@ -299,11 +307,13 @@ def prepare_static_build_linux(self): '--with-libxml-prefix={}'.format(self.prefix_dir), '--without-crypto', ], - cwd=libxslt_dir, + cwd=str(libxslt_dir), env=env, ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=libxslt_dir, env=env) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=libxslt_dir, env=env) + subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) + subprocess.check_output( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env + ) self.info('Building xmlsec1') if 'LDFLAGS' in env: @@ -311,7 +321,7 @@ def prepare_static_build_linux(self): else: env['LDFLAGS'] = '-lpthread' xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.run( + subprocess.check_output( [ './configure', prefix_arg, @@ -326,16 +336,18 @@ def prepare_static_build_linux(self): '--with-libxml={}'.format(self.prefix_dir), '--with-libxslt={}'.format(self.prefix_dir), ], - cwd=xmlsec1_dir, + cwd=str(xmlsec1_dir), env=env, ) - subprocess.run( + subprocess.check_output( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], - cwd=xmlsec1_dir, + cwd=str(xmlsec1_dir), env=env, ) - subprocess.run(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=xmlsec1_dir, env=env) + subprocess.check_output( + ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env + ) ext = self.ext_map['xmlsec'] ext.define_macros = [ @@ -374,12 +386,22 @@ def prepare_static_build_linux(self): ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] -src_root = Path('src') -sources = [str(p.absolute()) for p in src_root.rglob('*.c')] +if sys.version_info >= (3, 4): + src_root = Path(__file__).parent / 'src' + sources = [str(p.absolute()) for p in src_root.rglob('*.c')] +else: + import fnmatch + + src_root = os.path.join(os.path.dirname(__file__), 'src') + sources = [] + for root, _, files in os.walk(src_root): + for file in fnmatch.filter(files, '*.c'): + sources.append(os.path.join(root, file)) + pyxmlsec = Extension('xmlsec', sources=sources) setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig', 'lxml>=3.8'] -if sys.version_info < (3,): +if sys.version_info < (3, 4): setup_reqs.append('pathlib2') From 840b76132433cf2fecd26d2e5cdce01faafa284a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:52:53 +0200 Subject: [PATCH 107/378] more python 2 compat, win-specific Signed-off-by: oleg.hoefling --- setup.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 74ced1a2..dace07e8 100644 --- a/setup.py +++ b/setup.py @@ -127,12 +127,12 @@ def prepare_static_build_win(self): else: self.info('Retrieving "{}" to "{}"'.format(url, destfile)) urlcleanup() # work around FTP bug 27973 in Py2.7.12+ - urlretrieve(url, destfile) + urlretrieve(url, str(destfile)) for p in self.libs_dir.glob('*.zip'): - with zipfile.ZipFile(p) as f: + with zipfile.ZipFile(str(p)) as f: destdir = self.build_libs_dir - f.extractall(path=destdir) + f.extractall(path=str(destdir)) ext = self.ext_map['xmlsec'] ext.define_macros = [ From 0641dae4f24542bda04082d3618c54a8b408f01b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 22:58:56 +0200 Subject: [PATCH 108/378] pathlib imports on win don't hold Signed-off-by: oleg.hoefling --- setup.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index dace07e8..5247ef70 100644 --- a/setup.py +++ b/setup.py @@ -23,7 +23,9 @@ def info(self, message): self.announce(message, level=log.INFO) def run(self): - if sys.version_info < (3, 4): + if sys.version_info >= (3, 4): + from pathlib import Path + else: from pathlib2 import Path ext = self.ext_map['xmlsec'] From ad1306e363b12a23cca51f8dd5a3c40be28e093b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 23:14:05 +0200 Subject: [PATCH 109/378] add manylinux2010 builds on gh actions Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 36 +++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/manylinux2010.yml diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml new file mode 100644 index 00000000..eaa119c9 --- /dev/null +++ b/.github/workflows/manylinux2010.yml @@ -0,0 +1,36 @@ +name: manylinux2010 +on: [push] +jobs: + manylinux2010_x86_64: + runs-on: ubuntu-latest + container: quay.io/pypa/manylinux2010_x86_64 + strategy: + matrix: + python-abi: [cp27-cp27m, cp27-cp27mu, cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38] + steps: + - uses: actions/checkout@v1 + - name: Set environment variables + shell: bash + run: | + echo ::set-env name=PKGVER::$(python setup.py --version) + echo ::set-env name=STATIC_DEPS::true + - name: Install build dependencies + run: | + /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel -r requirements.txt + - name: Build linux_x86_64 wheel + run: | + /opt/python/${{ matrix.python-abi }}/bin/python setup.py bdist_wheel + - name: Label manylinux2010_x86_64 wheel + run: | + ls -la dist/ + auditwheel show dist/xmlsec-${PKGVER}-${{ matrix.python-abi }}-linux_x86_64.whl + auditwheel repair dist/xmlsec-${PKGVER}-${{ matrix.python-abi }}-linux_x86_64.whl + ls -l wheelhouse/ + auditwheel show wheelhouse/xmlsec-${PKGVER}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl + - name: Install test dependencies + run: | + /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt + /opt/python/${{ matrix.python-abi }}/bin/pip install xmlsec --only-binary=xmlsec --no-index --find-links=wheelhouse/ + - name: Run tests + run: | + /opt/python/${{ matrix.python-abi }}/bin/pytest -v From 8349740b8db32da82b714c89517dbf6627e8e386 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 23:19:48 +0200 Subject: [PATCH 110/378] more python 2 compat, linux-specific Signed-off-by: oleg.hoefling --- setup.py | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 5247ef70..306b9f94 100644 --- a/setup.py +++ b/setup.py @@ -194,21 +194,23 @@ def prepare_static_build_linux(self): if openssl_tar is None: self.info('OpenSSL source tar not found, downloading ...') openssl_tar = self.libs_dir / 'openssl.tar.gz' - urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), openssl_tar) + urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), str(openssl_tar)) # fetch zlib zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) if zlib_tar is None: self.info('zlib source tar not found, downloading ...') zlib_tar = self.libs_dir / 'zlib.tar.gz' - urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), zlib_tar) + urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), str(zlib_tar)) # fetch libiconv libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) if libiconv_tar is None: self.info('libiconv source tar not found, downloading ...') libiconv_tar = self.libs_dir / 'libiconv.tar.gz' - urlretrieve('https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), libiconv_tar) + urlretrieve( + 'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), str(libiconv_tar) + ) # fetch libxml2 libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.gz'), None) @@ -219,7 +221,7 @@ def prepare_static_build_linux(self): else: url = 'http://xmlsoft.org/sources/libxml2-{}.tar.gz'.format(self.libxml2_version) libxml2_tar = self.libs_dir / 'libxml2.tar.gz' - urlretrieve(url, libxml2_tar) + urlretrieve(url, str(libxml2_tar)) # fetch libxslt libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) @@ -230,7 +232,7 @@ def prepare_static_build_linux(self): else: url = 'http://xmlsoft.org/sources/libxslt-{}.tar.gz'.format(self.libxslt_version) libxslt_tar = self.libs_dir / 'libxslt.tar.gz' - urlretrieve(url, libxslt_tar) + urlretrieve(url, str(libxslt_tar)) # fetch xmlsec1 xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) @@ -238,7 +240,7 @@ def prepare_static_build_linux(self): self.info('xmlsec1 source tar not found, downloading ...') url = 'http://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' - urlretrieve(url, xmlsec1_tar) + urlretrieve(url, str(xmlsec1_tar)) for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): self.info('Unpacking {}'.format(file.name)) From c86e7467e06995cfbdf4adc11e727de16fa7cadd Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 23:33:28 +0200 Subject: [PATCH 111/378] fix wrong placement of environment variables in gh manylinux actions Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index eaa119c9..6a6a115a 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -9,15 +9,16 @@ jobs: python-abi: [cp27-cp27m, cp27-cp27mu, cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38] steps: - uses: actions/checkout@v1 + - name: Install build dependencies + run: | + /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel - name: Set environment variables shell: bash run: | echo ::set-env name=PKGVER::$(python setup.py --version) - echo ::set-env name=STATIC_DEPS::true - - name: Install build dependencies - run: | - /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel -r requirements.txt - name: Build linux_x86_64 wheel + env: + STATIC_DEPS: true run: | /opt/python/${{ matrix.python-abi }}/bin/python setup.py bdist_wheel - name: Label manylinux2010_x86_64 wheel From a2d0c6eed0e07cd016b620a4dd5be0c136cca4d1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 13 May 2020 23:38:08 +0200 Subject: [PATCH 112/378] fix version detection in gh manylinux actions Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 6a6a115a..d08c9673 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -15,7 +15,7 @@ jobs: - name: Set environment variables shell: bash run: | - echo ::set-env name=PKGVER::$(python setup.py --version) + echo ::set-env name=PKGVER::$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version) - name: Build linux_x86_64 wheel env: STATIC_DEPS: true From 00614322ae9bea1f4ab6fa21ecb168fa14141f15 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:01:26 +0200 Subject: [PATCH 113/378] gh manylinux actions: configure upload to testpypi Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index d08c9673..e4d1d5b4 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -35,3 +35,12 @@ jobs: - name: Run tests run: | /opt/python/${{ matrix.python-abi }}/bin/pytest -v + - name: Upload dist + env: + TWINE_NON_INTERACTIVE: true + TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.pypi_token }} + run: | + /opt/python/${{ matrix.python-abi }}/bin/pip install twine + /opt/python/${{ matrix.python-abi }}/bin/twine upload wheelhouse/xmlsec-${PKGVER}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl From d9a46aa3777f197e1556def130a3594ac5196545 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:22:46 +0200 Subject: [PATCH 114/378] upload dists on tag pushes only, enable pipeline on pull requests Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index e4d1d5b4..37e91dcc 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -1,5 +1,5 @@ name: manylinux2010 -on: [push] +on: [push, pull_request] jobs: manylinux2010_x86_64: runs-on: ubuntu-latest @@ -36,6 +36,7 @@ jobs: run: | /opt/python/${{ matrix.python-abi }}/bin/pytest -v - name: Upload dist + if: startsWith(github.ref, 'refs/tags/') env: TWINE_NON_INTERACTIVE: true TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ From 3fafcb54f8b2bdbef7cecaa6eea0a8508e57b6ca Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:37:48 +0200 Subject: [PATCH 115/378] add manylinux2010 action badge to readme Signed-off-by: oleg.hoefling --- README.rst | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 66b95a9c..e562a1ed 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,10 @@ python-xmlsec .. image:: https://travis-ci.org/mehcode/python-xmlsec.png?branch=master :target: https://travis-ci.org/mehcode/python-xmlsec -.. image:: https://ci.appveyor.com/api/projects/status/20rtt2wv96gag9cy?svg=true - :target: https://ci.appveyor.com/project/bgaifullin/python-xmlsec +.. image:: https://ci.appveyor.com/api/projects/status/ij87xk5wo8a39jua?svg=true + :target: https://ci.appveyor.com/project/hoefling/xmlsec +.. image:: https://github.com/mehcode/python-xmlsec/workflows/manylinux2010/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg From 70f201ca0b1684ccc6a8b41e74dc7e4acd4c6f99 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 2 May 2020 12:41:54 +0200 Subject: [PATCH 116/378] add deploy stage on tags to appveyor Signed-off-by: oleg.hoefling --- .appveyor.yml | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6945d269..2c3ac806 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,6 +1,9 @@ -version: 1.3.{build} - environment: + global: + TWINE_USERNAME: + secure: AIbDZTVaU3Ijr7mtxW7dlw== + TWINE_PASSWORD: + secure: YI+izt+hzh/czFuDCrne4XN78nQmT7jvcqe9uWvndqAUxhyXqr98GJ9FUSVPbqyWx+pW+5cKvh2PMdDEPJUcHMG8dtpHcosn3ndXnHGkHH3mwOnOduiUtrhlSEoIFwbZUhFRScYvfILGD8KM7RgcCiUUcner8QOFPiFX1zey8WVLynIj3c1rVe6Ola18pIUoL9D4NITNt5EWxexvr4vnkHmydk6dzWHBpiGsFujzccg+MoYN2ZjiN2JGSOykmEF/ matrix: - python: 27 - python: 27-x64 @@ -14,25 +17,25 @@ environment: - python: 38-x64 install: - - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% - - python -m pip.__main__ install -U pip wheel setuptools - - pip install -r requirements-test.txt + - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% + - python -m pip install -U pip wheel setuptools + - pip install -r requirements-test.txt build: off build_script: - # configure version - - ps: >- - If ($env:APPVEYOR_REPO_TAG -Eq "true" ) { - $version = "$env:APPVEYOR_REPO_TAG_NAME" - } Else { - $version = "$env:APPVEYOR_BUILD_VERSION.dev0" - } - $version | Set-Content version.txt - - python setup.py build bdist_wheel - - ps: Get-ChildItem dist\*.whl | % { pip install $_.FullName } + - python setup.py bdist_wheel test: off test_script: - - pip list - - py.test -v tests - - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + - pip list + - py.test -v tests + - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + + +deploy: on +deploy_script: + - ps: >- + If ($env:APPVEYOR_REPO_TAG -eq $TRUE) { + pip install twine + twine upload dist/*.whl + } From 2bddd6ca94e797efc1e985406a3958e84178594c Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 2 May 2020 15:13:28 +0200 Subject: [PATCH 117/378] use api token for pypi auth Signed-off-by: oleg.hoefling --- .appveyor.yml | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 2c3ac806..6158d7e3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,7 @@ environment: global: - TWINE_USERNAME: - secure: AIbDZTVaU3Ijr7mtxW7dlw== + TWINE_NON_INTERACTIVE: true + TWINE_USERNAME: __token__ TWINE_PASSWORD: secure: YI+izt+hzh/czFuDCrne4XN78nQmT7jvcqe9uWvndqAUxhyXqr98GJ9FUSVPbqyWx+pW+5cKvh2PMdDEPJUcHMG8dtpHcosn3ndXnHGkHH3mwOnOduiUtrhlSEoIFwbZUhFRScYvfILGD8KM7RgcCiUUcner8QOFPiFX1zey8WVLynIj3c1rVe6Ola18pIUoL9D4NITNt5EWxexvr4vnkHmydk6dzWHBpiGsFujzccg+MoYN2ZjiN2JGSOykmEF/ matrix: @@ -19,7 +19,6 @@ environment: install: - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% - python -m pip install -U pip wheel setuptools - - pip install -r requirements-test.txt build: off build_script: @@ -27,11 +26,11 @@ build_script: test: off test_script: - - pip list - - py.test -v tests + - pip install -r requirements-test.txt + - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist + - pytest -v - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - deploy: on deploy_script: - ps: >- From cdab489fb10fd4ab64b6565a3c0be0a6aa9e77e1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:51:47 +0200 Subject: [PATCH 118/378] fix appveyor config Signed-off-by: oleg.hoefling --- .appveyor.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 6158d7e3..9a831572 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -34,7 +34,7 @@ test_script: deploy: on deploy_script: - ps: >- - If ($env:APPVEYOR_REPO_TAG -eq $TRUE) { - pip install twine - twine upload dist/*.whl - } + If ($env:APPVEYOR_REPO_TAG -eq $TRUE) { + pip install twine + twine upload dist/*.whl + } From e06f4ae33098ccd8566380540d2e412ef7e25104 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:53:16 +0200 Subject: [PATCH 119/378] don't upload to pypi from travis Signed-off-by: oleg.hoefling --- .travis.yml | 11 ----------- 1 file changed, 11 deletions(-) diff --git a/.travis.yml b/.travis.yml index 3c87d2be..703322fb 100644 --- a/.travis.yml +++ b/.travis.yml @@ -46,14 +46,3 @@ after_success: before_deploy: - travis_retry pip install Sphinx - python setup.py build_sphinx -deploy: - skip_cleanup: true - skip_upload_docs: false - provider: pypi - user: mehcode - on: - tags: true - distributions: sdist bdist_wheel - python: '2.7' - password: - secure: KNBbGaiAWirptxcuLjqNVgQ9E3jc75kj2+A5MRh+XvDVf6xFLAhrNg0+p/a3d+Tdap4/W5retxDdafLoMJ80ftyJFWV+lnrDxBhcrT686HGXPb0FCn58+Mho0RhM7CSHJIM8E85pVUV5E6QrmgmNWG8KKEaF3Vs5RJBhlP/g7Bg= From d1c23fd34a00d904111d204563b7b1c8f4c9c19a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 00:56:23 +0200 Subject: [PATCH 120/378] remove version.txt Signed-off-by: oleg.hoefling --- version.txt | 1 - 1 file changed, 1 deletion(-) delete mode 100644 version.txt diff --git a/version.txt b/version.txt deleted file mode 100644 index e7526496..00000000 --- a/version.txt +++ /dev/null @@ -1 +0,0 @@ -1.0.1.dev0 From 71c86d0fb2e51de04cd143c7be3365d39011c6e2 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 01:01:14 +0200 Subject: [PATCH 121/378] force pytest to color the output Signed-off-by: oleg.hoefling --- .appveyor.yml | 2 +- .github/workflows/manylinux2010.yml | 2 +- .travis.yml | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 9a831572..13288bb0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -28,7 +28,7 @@ test: off test_script: - pip install -r requirements-test.txt - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - - pytest -v + - pytest -v --color=yes - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } deploy: on diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 37e91dcc..7c677dd6 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -34,7 +34,7 @@ jobs: /opt/python/${{ matrix.python-abi }}/bin/pip install xmlsec --only-binary=xmlsec --no-index --find-links=wheelhouse/ - name: Run tests run: | - /opt/python/${{ matrix.python-abi }}/bin/pytest -v + /opt/python/${{ matrix.python-abi }}/bin/pytest -v --color=yes - name: Upload dist if: startsWith(github.ref, 'refs/tags/') env: diff --git a/.travis.yml b/.travis.yml index 703322fb..77912fb9 100644 --- a/.travis.yml +++ b/.travis.yml @@ -38,7 +38,7 @@ install: - travis_retry pip install coverage codecov -r requirements-test.txt --upgrade --force-reinstall - travis_retry pip install -e "." - pip list -script: coverage run -m pytest -v tests +script: coverage run -m pytest -v tests --color=yes after_success: - lcov --capture --directory . --output-file coverage.info - lcov --list coverage.info From 1146b671b13f0bd671394dbd1a589d8f144e501f Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 10:18:30 +0200 Subject: [PATCH 122/378] exclude unnecessary files from sdist Signed-off-by: oleg.hoefling --- MANIFEST.in | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/MANIFEST.in b/MANIFEST.in index 9cafd112..6c47dc9c 100644 --- a/MANIFEST.in +++ b/MANIFEST.in @@ -1,6 +1,14 @@ -include src/* -include requirements*.txt -include LICENSE -include version.txt -include xmlsec_setupinfo.py -include xmlsec_extra.py +recursive-include src * +recursive-include tests * +prune */__pycache__ +prune .github +prune doc +exclude .appveyor.yml +exclude .editorconfig +exclude .travis.yml +exclude .gitattributes +exclude .gitignore +exclude requirements-test.txt +exclude requirements.txt +exclude xmlsec_extra.py +exclude xmlsec_setupinfo.py From 2fd2e091c82ce56fc2c0943a0de57ae28bdd2110 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 10:22:17 +0200 Subject: [PATCH 123/378] for the unlikely case of egg install, prohibit zipped installation Signed-off-by: oleg.hoefling --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 306b9f94..407d6267 100644 --- a/setup.py +++ b/setup.py @@ -439,4 +439,5 @@ def prepare_static_build_linux(self): 'Programming Language :: Python :: 3.8', 'Topic :: Text Processing :: Markup :: XML', ], + zip_safe=False, ) From 370351884aaac8c0ca175786f01e9bd8fce6cbe5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 10:31:38 +0200 Subject: [PATCH 124/378] package and publish sdist in a gh action Signed-off-by: oleg.hoefling --- .github/workflows/sdist.yml | 36 ++++++++++++++++++++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 .github/workflows/sdist.yml diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml new file mode 100644 index 00000000..0042862b --- /dev/null +++ b/.github/workflows/sdist.yml @@ -0,0 +1,36 @@ +name: sdist +on: [push, pull_request] +jobs: + sdist: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Set up Python 3.8 + uses: actions/setup-python@v1 + with: + python-version: 3.8 + - name: Install build dependencies + run: | + pip install --upgrade pip setuptools wheel + - name: Package source dist + run: | + python setup.py sdist + - name: Install test dependencies + run: | + sudo apt update + sudo apt install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl pkg-config + pip install --upgrade -r requirements-test.txt + pip install dist/xmlsec-$(python setup.py --version).tar.gz + - name: Run tests + run: | + pytest -v --color=yes + - name: Upload dist + if: startsWith(github.ref, 'refs/tags/') + env: + TWINE_NON_INTERACTIVE: true + TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ + TWINE_USERNAME: __token__ + TWINE_PASSWORD: ${{ secrets.pypi_token }} + run: | + pip install twine + twine upload dist/xmlsec-*.tar.gz From dde6190eccdf0588ab854c7076eb95279e6b5c73 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 11:28:55 +0200 Subject: [PATCH 125/378] add testpypi token to appveyor for final testing Signed-off-by: oleg.hoefling --- .appveyor.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index 13288bb0..d0c4d701 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,9 +1,10 @@ environment: global: TWINE_NON_INTERACTIVE: true + TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ TWINE_USERNAME: __token__ TWINE_PASSWORD: - secure: YI+izt+hzh/czFuDCrne4XN78nQmT7jvcqe9uWvndqAUxhyXqr98GJ9FUSVPbqyWx+pW+5cKvh2PMdDEPJUcHMG8dtpHcosn3ndXnHGkHH3mwOnOduiUtrhlSEoIFwbZUhFRScYvfILGD8KM7RgcCiUUcner8QOFPiFX1zey8WVLynIj3c1rVe6Ola18pIUoL9D4NITNt5EWxexvr4vnkHmydk6dzWHBpiGsFujzccg+MoYN2ZjiN2JGSOykmEF/ + secure: YI+izt+hzh/czFuDCrne4cyTkNhdK/svjrWoIkN3nurz1LO1/YUb+zl8ln6hlMONaPhWLDI9YqmCobf3XdQVa8pclSCRiEtxg1HENmVOLJTS1IQCOMZhQjfXt5iNH5ov601/pgS367akiuGryGUoPkhcmJ9oD8aRH9dZ+Abh+PYPRMa3ka4U3SLcIHgzRUizLvkd73+Z5S4tjwjnDa1XHDnt/fZbeLjVL7T/4B2bWxnBVvHAckV/MGeOX3XgSK3UWdpEDTsg4ns0X0OubSziww== matrix: - python: 27 - python: 27-x64 From 539d2dd4a8f9fe1ff251adaa49091fe3b180034d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 21:09:04 +0200 Subject: [PATCH 126/378] adjust libxml2 compile options to what lxml uses in its static build Signed-off-by: oleg.hoefling --- setup.py | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 407d6267..8df42520 100644 --- a/setup.py +++ b/setup.py @@ -289,6 +289,10 @@ def prepare_static_build_linux(self): [ './configure', prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + '--enable-rebuild-docs=no', + '--without-lzma', '--without-python', '--with-iconv={}'.format(self.prefix_dir), '--with-zlib={}'.format(self.prefix_dir), @@ -307,9 +311,11 @@ def prepare_static_build_linux(self): [ './configure', prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', '--without-python', - '--with-libxml-prefix={}'.format(self.prefix_dir), '--without-crypto', + '--with-libxml-prefix={}'.format(self.prefix_dir), ], cwd=str(libxslt_dir), env=env, From ba26be5f825cf6a1a6131289df599c8eb37c95d5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 23:09:37 +0200 Subject: [PATCH 127/378] use static deps when testing packaged sdist Signed-off-by: oleg.hoefling --- .github/workflows/sdist.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 0042862b..a6eda5bd 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -16,9 +16,9 @@ jobs: run: | python setup.py sdist - name: Install test dependencies + env: + STATIC_DEPS: true run: | - sudo apt update - sudo apt install -y libxml2-dev libxmlsec1-dev libxmlsec1-openssl pkg-config pip install --upgrade -r requirements-test.txt pip install dist/xmlsec-$(python setup.py --version).tar.gz - name: Run tests From c34245b568a8c23013a50dda952045f6d7ec5457 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 17 May 2020 23:35:31 +0200 Subject: [PATCH 128/378] better messages on errors Signed-off-by: oleg.hoefling --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index 8df42520..149743e6 100644 --- a/setup.py +++ b/setup.py @@ -33,7 +33,7 @@ def run(self): self.static = os.environ.get('STATIC_DEPS', False) if self.static or sys.platform == 'win32': - self.info('STATIC_DEPS is set; starting build of static deps on {}'.format(sys.platform)) + self.info('starting static build on {}'.format(sys.platform)) buildroot = Path('build', 'tmp') self.prefix_dir = buildroot / 'prefix' @@ -61,7 +61,7 @@ def run(self): raise DistutilsError('xmlsec1 is not installed or not in path.') if config is None or not config.get('libraries'): - raise DistutilsError('Bad or uncomplete result returned from pkg-config.') + raise DistutilsError('Bad or incomplete result returned from pkg-config.') ext.define_macros.extend(config['define_macros']) ext.include_dirs.extend(config['include_dirs']) From aeb14d3fc6ce90c779b650eaa99e3142e7e5a541 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 17:39:54 +0200 Subject: [PATCH 129/378] read version from local installation, configure crossrefs to stdlib, ignore errors when ref'ing to lxml stuff Signed-off-by: oleg.hoefling --- .travis.yml | 4 +-- doc/source/conf.py | 61 +++++++++++++++++++++++++++++++--------------- 2 files changed, 44 insertions(+), 21 deletions(-) diff --git a/.travis.yml b/.travis.yml index 77912fb9..b9cc5588 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,5 +44,5 @@ after_success: - lcov --list coverage.info - codecov --file coverage.info before_deploy: -- travis_retry pip install Sphinx -- python setup.py build_sphinx +- travis_retry pip install Sphinx importlib-metadata packaging +- sphinx-build -EWanb html doc/source build/sphinx diff --git a/doc/source/conf.py b/doc/source/conf.py index 0bdbb022..d03702ca 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -16,11 +16,19 @@ # add these directories to sys.path here. If the directory is relative to the # documentation root, use os.path.abspath to make it absolute, like shown here. # -import os -# import sys +import sys + +from packaging.version import parse + # sys.path.insert(0, os.path.abspath('.')) +if sys.version_info >= (3, 8): + from importlib import metadata as importlib_metadata +else: + import importlib_metadata + + # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. @@ -30,8 +38,7 @@ # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. -extensions = ['sphinx.ext.autodoc', - 'sphinx.ext.viewcode'] +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] # Add any paths that contain templates here, relative to this directory. templates_path = ['_templates'] @@ -54,10 +61,11 @@ # |version| and |release|, also used in various other places throughout the # built documents. # -# The short X.Y version. -version = os.getenv("TRAVIS_TAG", '1.0.1') # The full version, including alpha/beta/rc tags. -release = version +release = importlib_metadata.version('xmlsec') +# The short X.Y version. +parsed = parse(release) +version = '{}.{}'.format(parsed.major, parsed.minor) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. @@ -109,15 +117,12 @@ # The paper size ('letterpaper' or 'a4paper'). # # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). # # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. # # 'preamble': '', - # Latex figure (float) alignment # # 'figure_align': 'htbp', @@ -127,8 +132,13 @@ # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ - (master_doc, 'python-xmlsec.tex', u'python-xmlsec Documentation', - u'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}', 'manual'), + ( + master_doc, + 'python-xmlsec.tex', + u'python-xmlsec Documentation', + u'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}', + 'manual', + ) ] @@ -136,10 +146,7 @@ # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). -man_pages = [ - (master_doc, 'python-xmlsec', u'python-xmlsec Documentation', - [author], 1) -] +man_pages = [(master_doc, 'python-xmlsec', u'python-xmlsec Documentation', [author], 1)] # -- Options for Texinfo output ------------------------------------------- @@ -148,9 +155,25 @@ # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ - (master_doc, 'python-xmlsec', u'python-xmlsec Documentation', - author, 'python-xmlsec', 'One line description of project.', - 'Miscellaneous'), + ( + master_doc, + 'python-xmlsec', + u'python-xmlsec Documentation', + author, + 'python-xmlsec', + 'One line description of project.', + 'Miscellaneous', + ) ] autodoc_member_order = 'groupwise' + +autodoc_docstring_signature = True + +intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} + +nitpick_ignore = [ + # lxml doesn't have an intersphinx docs + # https://lxml.de/api/lxml.etree._Element-class.html + ('py:class', 'lxml.etree._Element') +] From 1a7ff18fc1bd5bf68c81c16cfbc43d46999de2b5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 18:44:16 +0200 Subject: [PATCH 130/378] add signatures to xmlsec docstrings, add missing input and return types, improvements to code highlighting Signed-off-by: oleg.hoefling --- src/ds.c | 52 ++++++++---- src/enc.c | 64 +++++++++------ src/keys.c | 76 +++++++++++++----- src/main.c | 8 +- src/template.c | 210 +++++++++++++++++++++++++++++++++---------------- src/tree.c | 42 +++++++--- 6 files changed, 312 insertions(+), 140 deletions(-) diff --git a/src/ds.c b/src/ds.c index 5986f566..44d046e0 100644 --- a/src/ds.c +++ b/src/ds.c @@ -110,10 +110,14 @@ static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void } static const char PyXmlSec_SignatureContextRegisterId__doc__[] = \ + "register_id(node, id_attr = 'ID', id_ns = None) -> None\n" "Registers new id.\n\n" ":param node: the pointer to XML node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param id_attr: the attribute\n" - ":param id_ns: the namespace\n"; + ":type id_attr: :class:`str`\n" + ":param id_ns: the namespace (optional)\n" + ":type id_ns: :class:`str` or :data:`None`"; static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", "id_attr", "id_ns", NULL}; @@ -166,8 +170,10 @@ static PyObject* PyXmlSec_SignatureContextRegisterId(PyObject* self, PyObject* a } static const char PyXmlSec_SignatureContextSign__doc__[] = \ + "sign(node) -> None\n" "Signs according to the signature template.\n\n" - ":param node: the pointer to node with signature template\n"; + ":param node: the pointer to :xml:`` node with signature template\n" + ":type node: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; @@ -197,9 +203,12 @@ static PyObject* PyXmlSec_SignatureContextSign(PyObject* self, PyObject* args, P } static const char PyXmlSec_SignatureContextVerify__doc__[] = \ + "verify(node) -> None\n" "Verifies according to the signature template.\n\n" - ":param node: he pointer with node\n" - ":return: None if success otherwise raises VerificationError\n"; + ":param node: the pointer with :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: :data:`None` on success\n" + ":raise VerificationError: on failure\n"; static PyObject* PyXmlSec_SignatureContextVerify(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; @@ -287,10 +296,14 @@ static int PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext* ctx, const xmlS } static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \ - "Signs binary data *data* with *algorithm*.\n\n" + "sign_binary(bytes, transform) -> bytes\n" + "Signs binary data ``data`` with algorithm ``transform``.\n\n" ":param bytes: the binary data\n" + ":type bytes: :class:`bytes`\n" ":param transform: the signature algorithm\n" - ":return: the signature\n"; + ":type transform: :class:`Transform`\n" + ":return: the signature\n" + ":rtype: :class:`bytes`"; static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", NULL}; PyXmlSec_SignatureContext* ctx = (PyXmlSec_SignatureContext*)self; @@ -322,11 +335,16 @@ static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* a } static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \ + "verify_binary(bytes, transform, signature) -> None\n" "Verifies signature for binary data.\n\n" ":param bytes: the binary data\n" + ":type bytes: :class:`bytes`\n" ":param transform: the signature algorithm\n" + ":type transform: :class:`Transform`\n" ":param signature: the signature\n" - ":return: None if success otherwise raises VerificationError\n"; + ":type signature: :class:`bytes`\n" + ":return: :data:`None` on success\n" + ":raise VerificationError: on failure"; static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "bytes", "transform", "signature", NULL}; @@ -372,9 +390,10 @@ static PyObject* PyXmlSec_SignatureContextVerifyBinary(PyObject* self, PyObject* } static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \ - "Enables use of *t* as reference transform.\n\n"\ - "Note: by default, all transforms are enabled. The first call of\n"\ - "`enable_reference_transform` will switch to explicitly enabled transforms.\n\n" + "enable_reference_transform(transform) -> None\n" + "Enables use of ``transform`` as reference transform.\n\n" + ".. note:: by default, all transforms are enabled. The first call of " + ":meth:`~SignatureContext.enable_reference_transform` will switch to explicitly enabled transforms.\n\n" ":param transform: the transform klass.\n"; static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -406,9 +425,10 @@ static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* sel } static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \ - "Enables use of *t* as signature transform.\n\n"\ - "Note: by default, all transforms are enabled. The first call of\n"\ - "`enable_signature_transform` will switch to explicitly enabled transforms.\n\n" + "enable_signature_transform(transform) -> None\n" + "Enables use of ``transform`` as signature transform.\n\n" + ".. note:: by default, all transforms are enabled. The first call of " + ":meth:`~SignatureContext.enable_signature_transform` will switch to explicitly enabled transforms.\n\n" ":param transform: the transform klass.\n"; static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -439,8 +459,10 @@ static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* sel } static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \ - "Adds selected *KeyData* to the list of enabled key data list.\n\n" - ":param keydata_list: the list.\n"; + "set_enabled_key_data(keydata_list) -> None\n" + "Adds selected :class:`KeyData` to the list of enabled key data list.\n\n" + ":param keydata_list: the list\n" + ":type keydata_list: :class:`list` of :class:`KeyData`"; static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "keydata_list", NULL}; diff --git a/src/enc.c b/src/enc.c index 199e94a6..02c01d8a 100644 --- a/src/enc.c +++ b/src/enc.c @@ -114,7 +114,8 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi } static const char PyXmlSec_EncryptionContextReset__doc__[] = \ - "Resets *context*, user settings are not touched.\n"; + "reset() -> None\n"\ + "Reset this context, user settings are not touched.\n"; static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, PyObject* kwargs) { PyXmlSec_EncryptionContext* ctx = (PyXmlSec_EncryptionContext*)self; @@ -128,11 +129,15 @@ static PyObject* PyXmlSec_EncryptionContextReset(PyObject* self, PyObject* args, } static const char PyXmlSec_EncryptionContextEncryptBinary__doc__[] = \ - "Encrypts binary *data* according to `EncryptedData` template *template*\n"\ - "Note: *template* is modified in place.\n\n" - ":param template: the pointer to template node\n" + "encrypt_binary(template, data) -> lxml.etree._Element\n" + "Encrypts binary ``data`` according to ``EncryptedData`` template ``template``.\n\n" + ".. note:: ``template`` is modified in place.\n\n" + ":param template: the pointer to :xml:`` template node\n" + ":type template: :class:`lxml.etree._Element`\n" ":param data: the data\n" - ":return: the resulting subtree\n"; + ":type data: :class:`bytes`\n" + ":return: the resulting :xml:`` subtree\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "data", NULL}; @@ -189,14 +194,18 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume } static const char PyXmlSec_EncryptionContextEncryptXml__doc__[] = \ - "Encrpyts *node* using *template*.\n" \ - "Note: The `Type` attribute of *template* decides whether *node* itself is encrypted\n"\ - "(`http://www.w3.org/2001/04/xmlenc#Element`) or its content (`http://www.w3.org/2001/04/xmlenc#Content`).\n"\ - "It must have one of these two values (or an exception is raised).\n"\ - "The operation modifies the tree and removes replaced nodes.\n"\ - ":param template: the pointer to template node\n"\ - ":param node: the pointer to node for encryption\n"\ - ":return: the pointer to newly created node\n"; + "encrypt_xml(template, node) -> lxml.etree._Element\n" + "Encrypts ``node`` using ``template``.\n\n" + ".. note:: The ``\"Type\"`` attribute of ``template`` decides whether ``node`` itself " + "(``http://www.w3.org/2001/04/xmlenc#Element``) or its content (``http://www.w3.org/2001/04/xmlenc#Content``) is encrypted.\n" + " It must have one of these two values (or an exception is raised).\n" + " The operation modifies the tree and removes replaced nodes.\n\n" + ":param template: the pointer to :xml:`` template node\n\n" + ":type template: :class:`lxml.etree._Element`\n" + ":param node: the pointer to node for encryption\n\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "node", NULL}; @@ -271,10 +280,15 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* } static const char PyXmlSec_EncryptionContextEncryptUri__doc__[] = \ - "Encrypts binary data obtained from *uri* according to *template*.\n\n" - ":param template: the pointer to template node\n" + "encrypt_uri(template, uri) -> lxml.etree._Element\n" + "Encrypts binary data obtained from ``uri`` according to ``template``.\n\n" + ".. note:: ``template`` is modified in place.\n\n" + ":param template: the pointer to :xml:`` template node\n" + ":type template: :class:`lxml.etree._Element`\n" ":param uri: the URI\n" - ":return: the resulting subtree\n"; + ":type uri: :class:`str`\n" + ":return: the resulting :xml:`` subtree\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "template", "uri", NULL}; @@ -306,14 +320,16 @@ static PyObject* PyXmlSec_EncryptionContextEncryptUri(PyObject* self, PyObject* } static const char PyXmlSec_EncryptionContextDecrypt__doc__[] = \ - "Decrypts *node* (an `EncryptedData` or `EncryptedKey` element) and return the result.\n"\ - "The decryption may result in binary data or an XML subtree.\n"\ - "In the former case, the binary data is returned. In the latter case,\n"\ - "the input tree is modified and a reference to the decrypted XML subtree is returned.\n"\ - "If the operation modifies the tree, it removes replaced nodes.\n"\ - ":param node: the pointer to or node\n" - ":return: depends on input parameters\n"; - + "decrypt(node)\n" + "Decrypts ``node`` (an ``EncryptedData`` or ``EncryptedKey`` element) and returns the result. " + "The decryption may result in binary data or an XML subtree. " + "In the former case, the binary data is returned. In the latter case, " + "the input tree is modified and a reference to the decrypted XML subtree is returned.\n" + "If the operation modifies the tree, it removes replaced nodes.\n\n" + ":param node: the pointer to :xml:`` or :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: depends on input parameters\n" + ":rtype: :class:`lxml.etree._Element` or :class:`bytes`"; static PyObject* PyXmlSec_EncryptionContextDecrypt(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "node", NULL}; diff --git a/src/keys.c b/src/keys.c index 1b660d25..fadc875a 100644 --- a/src/keys.c +++ b/src/keys.c @@ -68,11 +68,16 @@ static PyObject* PyXmlSec_Key__copy__(PyObject* self) { } static const char PyXmlSec_KeyFromMemory__doc__[] = \ + "from_memory(data, format, password = None) -> xmlsec.Key\n" "Loads PKI key from memory.\n\n" ":param data: the binary key data\n" + ":type data: :class:`str` or :class:`bytes`\n" ":param format: the key file format\n" - ":param password: the key file password\n" - ":return: pointer to newly created key\n"; + ":type format: :class:`int`\n" + ":param password: the key file password (optional)\n" + ":type password: :class:`str` or :data:`None`\n" + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeyFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", "password", NULL}; @@ -112,11 +117,17 @@ static PyObject* PyXmlSec_KeyFromMemory(PyObject* self, PyObject* args, PyObject } static const char PyXmlSec_KeyFromFile__doc__[] = \ + "from_file(file, format, password = None) -> xmlsec.Key\n" "Loads PKI key from a file.\n\n" ":param file: the file object or file path\n" + ":type file: :class:`str`, :class:`bytes`, any :class:`~os.PathLike`, " + ":class:`~typing.BinaryIO` or :class:`~typing.TextIO`\n" ":param format: the key file format\n" - ":param password: the key file password\n" - ":return: pointer to newly created key\n"; + ":type format: :class:`int`\n" + ":param password: the key file password (optional)\n" + ":type password: :class:`str` or :data:`None`\n" + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "file", "format", "password", NULL}; @@ -175,11 +186,15 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* } static const char PyXmlSec_KeyGenerate__doc__[] = \ - "Generates key of kind *data* with *size* and *type*.\n\n" + "generate(klass, size, type) -> xmlsec.Key\n" + "Generates key of kind ``klass`` with ``size`` and ``type``.\n\n" ":param klass: the requested key klass (rsa, dsa, aes, ...)\n" ":param size: the new key size (in bits!)\n" + ":type size: :class:`int`\n" ":param type: the new key type (session, permanent, ...)\n" - ":return: pointer to newly created key\n"; + ":type type: :class:`int`\n" + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeyGenerate(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "klass", "size", "type", NULL}; @@ -214,10 +229,13 @@ static PyObject* PyXmlSec_KeyGenerate(PyObject* self, PyObject* args, PyObject* } static const char PyXmlSec_KeyFromBinaryFile__doc__[] = \ - "Loads (symmetric) key of kind *data* from *filename*.\n\n" + "from_binary_file(klass, filename) -> xmlsec.Key\n" + "Loads (symmetric) key of kind ``klass`` from ``filename``.\n\n" ":param klass: the key value data klass\n" ":param filename: the key binary filename\n" - ":return: pointer to newly created key\n"; + ":type filename: :class:`str`, :class:`bytes` or any :class:`~os.PathLike`\n" + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "klass", "filename", NULL}; @@ -261,10 +279,13 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb } static const char PyXmlSec_KeyFromBinaryData__doc__[] = \ - "Loads (symmetric) key of kind *klass* from *data*.\n\n" + "from_binary_data(klass, data) -> xmlsec.Key\n" + "Loads (symmetric) key of kind ``klass`` from ``data``.\n\n" ":param klass: the key value data klass\n" ":param data: the key binary data\n" - ":return: pointer to newly created key\n"; + ":type data: :class:`str` or :class:`bytes`\n" + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeyFromBinaryData(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "klass", "data", NULL}; @@ -304,9 +325,12 @@ static PyObject* PyXmlSec_KeyFromBinaryData(PyObject* self, PyObject* args, PyOb } static const char PyXmlSec_KeyCertFromMemory__doc__[] = \ + "load_cert_from_memory(data, format) -> None\n" "Loads certificate from memory.\n\n" ":param data: the certificate binary data\n" - ":param format: the certificate file format\n"; + ":type data: :class:`str` or :class:`bytes`\n" + ":param format: the certificate file format\n" + ":type format: :class:`int`"; static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", NULL}; @@ -340,9 +364,13 @@ static PyObject* PyXmlSec_KeyCertFromMemory(PyObject* self, PyObject* args, PyOb } static const char PyXmlSec_KeyCertFromFile__doc__[] = \ + "load_cert_from_file(file, format) -> None\n" "Loads certificate from file.\n\n" ":param file: the file object or file path\n" - ":param format: the certificate file format\n"; + ":type file: :class:`str`, :class:`bytes`, any :class:`~os.PathLike`, " + ":class:`~typing.BinaryIO` or :class:`~typing.TextIO`\n" + ":param format: the certificate file format\n" + ":type format: :class:`int`"; static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "file", "format", NULL}; @@ -393,7 +421,7 @@ static PyObject* PyXmlSec_KeyCertFromFile(PyObject* self, PyObject* args, PyObje return NULL; } -static const char PyXmlSec_KeyName__doc__[] = "the name of *key*.\n"; +static const char PyXmlSec_KeyName__doc__[] = "the name of this key.\n"; static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { PyXmlSec_Key* key = (PyXmlSec_Key*)self; const char* cname; @@ -588,8 +616,10 @@ static void PyXmlSec_KeysManager__del__(PyObject* self) { } static const char PyXmlSec_KeysManagerAddKey__doc__[] = \ - "Adds a copy of *key* to keys manager\n\n" - ":param key: the pointer to key\n"; + "add_key(key: xmlsec.Key) -> None\n" + "Adds a copy of ``key`` to keys manager\n\n" + ":param key: the pointer to key\n" + ":type key: :class:`~xmlsec.Key`"; static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "key", NULL}; @@ -633,10 +663,14 @@ static PyObject* PyXmlSec_KeysManagerAddKey(PyObject* self, PyObject* args, PyOb } static const char PyXmlSec_KeysManagerLoadCert__doc__[] = \ - "Loads certificate from *filename*.\n\n" + "load_cert(filename, format, type) -> None\n" + "Loads certificate from ``filename``.\n\n" ":param filename: the certificate file\n" + ":type filename: :class:`str`, :class:`bytes` or any :class:`~os.PathLike`\n" ":param format: the certificate file format\n" - ":param type: the flag that indicates is the certificate in filename trusted or not\n"; + ":type format: :class:`int`\n" + ":param type: the flag that indicates is the certificate in filename trusted or not\n" + ":type type: :class:`int`"; static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "filename", "format", "type", NULL}; @@ -673,10 +707,14 @@ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, Py } static const char PyXmlSec_KeysManagerLoadCertFromMemory__doc__[] = \ - "Loads certificate from *data*\n\n" + "load_cert_from_memory(data, format, type) -> None\n" + "Loads certificate from ``data``\n\n" ":param data: the certificate binary data\n" + ":type data: :class:`str` or :class:`bytes`\n" ":param format: the certificate file format\n" - ":param type: the flag that indicates is the certificate in filename trusted or not\n"; + ":type format: :class:`int`\n" + ":param type: the flag that indicates is the certificate in filename trusted or not\n" + ":type type: :class:`int`"; static PyObject* PyXmlSec_KeysManagerLoadCertFromMemory(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "data", "format", "type", NULL}; diff --git a/src/main.c b/src/main.c index de98a0b7..85f457f2 100644 --- a/src/main.c +++ b/src/main.c @@ -91,9 +91,10 @@ static int PyXmlSec_Init(void) { } static char PyXmlSec_PyInit__doc__[] = \ + "init() -> None\n" "Initializes the library for general operation.\n\n" "This is called upon library import and does not need to be called\n" - "again *shutdown* is called explicitly).\n"; + "again :func:`~.shutdown` is called explicitly).\n"; static PyObject* PyXmlSec_PyInit(PyObject *self) { if (PyXmlSec_Init() < 0) { return NULL; @@ -102,6 +103,7 @@ static PyObject* PyXmlSec_PyInit(PyObject *self) { } static char PyXmlSec_PyShutdown__doc__[] = \ + "shutdown() -> None\n" "Shutdowns the library and cleanup any leftover resources.\n\n" "This is called automatically upon interpreter termination and\n" "should not need to be called explicitly."; @@ -111,8 +113,10 @@ static PyObject* PyXmlSec_PyShutdown(PyObject* self) { } static char PyXmlSec_PyEnableDebugOutput__doc__[] = \ + "enable_debug_trace(enabled) -> None\n" "Enables or disables calling LibXML2 callback from the default errors callback.\n\n" - ":param enable_debug_trace: flag, debug trace is enabled or disabled"; + ":param enabled: flag, debug trace is enabled or disabled\n" + ":type enabled: :class:`bool`"; static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "enabled", NULL}; PyObject* enabled = Py_True; diff --git a/src/template.c b/src/template.c index 9a68dbd7..e38945b4 100644 --- a/src/template.c +++ b/src/template.c @@ -18,14 +18,19 @@ #define PYXMLSEC_TEMPLATES_DOC "Xml Templates processing" static char PyXmlSec_TemplateCreate__doc__[] = \ - "Creates new node with the mandatory , ," - " and children and sub-children.\n\n" + "create(node, c14n_method, sign_method, id = None, ns = None) -> lxml.etree._Element\n" + "Creates new :xml:`` node with the mandatory :xml:``, :xml:``, " + ":xml:`` and :xml:`` children and sub-children.\n\n" ":param node: the signature node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param c14n_method: the signature canonicalization method\n" ":param sign_method: the signature method\n" ":param id: the node id (optional)\n" - ":param ns: the namespace prefix for the signature element (e.g. \"dsig\") (optional)\n" - ":return: the pointer to newly created node\n"; + ":type id: :class:`str` or :data:`None`\n" + ":param ns: the namespace prefix for the signature element (e.g. ``\"dsig\"``) (optional)\n" + ":type ns: :class:`str` or :data:`None`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "c14n_method", "sign_method", "id", "ns", "name", NULL}; @@ -60,14 +65,20 @@ static PyObject* PyXmlSec_TemplateCreate(PyObject* self, PyObject *args, PyObjec } static char PyXmlSec_TemplateAddReference__doc__[] = \ - "Adds node with given URI (uri ) Id (id ) and Type (type ) attributes and\n" - "the required children and to the child of *node*.\n\n" - ":param node: the pointer to node\n" + "add_reference(node, digest_method, id = None, uri = None, type = None) -> lxml.etree._Element\n" + "Adds :xml:`` node with given ``\"URI\"`` (``uri``), ``\"Id\"`` (``id``) and ``\"Type\"`` (``type``) attributes and " + "the required children :xml:`` and :xml:`` to the :xml:`` child of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param digest_method: the reference digest method\n" ":param id: the node id (optional)\n" - ":param uri: the reference node uri (optional)\n" + ":type id: :class:`str` or :data:`None`\n" + ":param uri: the reference node URI (optional)\n" + ":type uri: :class:`str` or :data:`None`\n" ":param type: the reference node type (optional)\n" - ":return: the pointer to newly created node\n"; + ":type type: :class:`str` or :data:`None`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "digest_method", "id", "uri", "type", NULL}; @@ -101,10 +112,13 @@ static PyObject* PyXmlSec_TemplateAddReference(PyObject* self, PyObject *args, P } static char PyXmlSec_TemplateAddTransform__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "add_transform(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param transform: the transform method id\n" - ":return: the pointer to newly created node\n"; + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "transform", NULL}; @@ -135,10 +149,14 @@ static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, P } static char PyXmlSec_TemplateEnsureKeyInfo__doc__[] = \ - "Adds (if necessary) node to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "ensure_key_info(node, id = None) -> lxml.etree._Element\n" + "Adds (if necessary) :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param id: the node id (optional)\n" - ":return: the pointer to newly created node\n"; + ":type id: :class:`str` or :data:`None`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "id", NULL}; @@ -169,10 +187,14 @@ static PyObject* PyXmlSec_TemplateEnsureKeyInfo(PyObject* self, PyObject *args, } static char PyXmlSec_TemplateAddKeyName__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "add_key_name(node, name = None) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param name: the key name (optional)\n" - ":return: the pointer to the newly created node\n"; + ":type name: :class:`str` or :data:`None`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", NULL}; @@ -203,9 +225,12 @@ static PyObject* PyXmlSec_TemplateAddKeyName(PyObject* self, PyObject *args, PyO } static char PyXmlSec_TemplateAddKeyValue__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "add_key_value(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -235,9 +260,12 @@ static PyObject* PyXmlSec_TemplateAddKeyValue(PyObject* self, PyObject *args, Py } static char PyXmlSec_TemplateAddX509Data__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "add_x509_data(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`\n"; static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -267,9 +295,12 @@ static PyObject* PyXmlSec_TemplateAddX509Data(PyObject* self, PyObject *args, Py } static char PyXmlSec_TemplateAddX509DataAddIssuerSerial__doc__[] = \ - "Adds node to the given node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "x509_data_add_issuer_serial(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the given :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -299,10 +330,14 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddIssuerSerial(PyObject* self, PyO } static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "x509_issuer_serial_add_issuer_name(node, name = None) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param name: the issuer name (optional)\n" - ":return: the pointer to the newly created node\n"; + ":type name: :class:`str` or :data:`None`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", NULL}; @@ -334,10 +369,14 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerName(PyObject* } static char PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber__doc__[] = \ - "Adds node to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "x509_issuer_serial_add_serial_number(node, serial = None) -> lxml.etree._Element\n" + "Adds :xml:`` node to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param serial: the serial number (optional)\n" - ":return: the pointer to the newly created node\n"; + ":type serial: :class:`str` or :data:`None`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "serial", NULL}; @@ -369,9 +408,12 @@ static PyObject* PyXmlSec_TemplateAddX509DataIssuerSerialAddIssuerSerialNumber(P } static char PyXmlSec_TemplateAddX509DataAddSubjectName__doc__[] = \ - "Adds node to the given node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "x509_data_add_subject_name(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the given :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -402,9 +444,12 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSubjectName(PyObject* self, PyOb } static char PyXmlSec_TemplateAddX509DataAddSKI__doc__[] = \ - "Adds node to the given node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "x509_data_add_ski(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the given :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -435,9 +480,12 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddSKI(PyObject* self, PyObject *ar } static char PyXmlSec_TemplateAddX509DataAddCertificate__doc__[] = \ - "Adds node to the given node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "x509_data_add_certificate(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the given :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -468,9 +516,12 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCertificate(PyObject* self, PyOb } static char PyXmlSec_TemplateAddX509DataAddCRL__doc__[] = \ - "Adds node to the given node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to the newly created node\n"; + "x509_data_add_crl(node) -> lxml.etree._Element\n" + "Adds :xml:`` node to the given :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -501,13 +552,19 @@ static PyObject* PyXmlSec_TemplateAddX509DataAddCRL(PyObject* self, PyObject *ar } static char PyXmlSec_TemplateAddEncryptedKey__doc__[] = \ - "Adds node with given attributes to the node of *node*.\n\n" - ":param node: the pointer to node\n" + "add_encrypted_key(node, method, id = None, type = None, recipient = None) -> lxml.etree._Element\n" + "Adds :xml:`` node with given attributes to the :xml:`` node of *node*.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param method: the encryption method\n" - ":param id: the Id attribute (optional)\n" - ":param type: the Type attribute (optional)\n" - ":param recipient: the Recipient attribute (optional)\n" - ":return: the pointer to the newly created node\n"; + ":param id: the ``\"Id\"`` attribute (optional)\n" + ":type id: :class:`str` or :data:`None`\n" + ":param type: the ``\"Type\"`` attribute (optional)\n" + ":type type: :class:`str` or :data:`None`\n" + ":param recipient: the ``\"Recipient\"`` attribute (optional)\n" + ":type recipient: :class:`str` or :data:`None`\n" + ":return: the pointer to the newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "method", "id", "type", "recipient", NULL}; @@ -542,15 +599,23 @@ static PyObject* PyXmlSec_TemplateAddEncryptedKey(PyObject* self, PyObject *args } static char PyXmlSec_TemplateCreateEncryptedData__doc__[] = \ - "Creates new <{ns}:EncryptedData /> node for encryption template.\n\n" + "encrypted_data_create(node, method, id = None, type = None, mime_type = None, encoding = None, ns = None) -> lxml.etree._Element\n" + "Creates new :xml:`<{ns}:EncryptedData />` node for encryption template.\n\n" ":param node: the pointer to signature node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param method: the encryption method\n" - ":param id: the Id attribute (optional)\n" - ":param type: the Type attribute (optional)\n" - ":param mime_type: the Recipient attribute (optional)\n" - ":param encoding: the MimeType attribute (optional)\n" + ":param id: the ``\"Id\"`` attribute (optional)\n" + ":type id: :class:`str` or :data:`None`\n" + ":param type: the ``\"Type\"`` attribute (optional)\n" + ":type type: :class:`str` or :data:`None`\n" + ":param mime_type: the ``\"Recipient\"`` attribute (optional)\n" + ":type mime_type: :class:`str` or :data:`None`\n" + ":param encoding: the ``\"MimeType\"`` attribute (optional)\n" + ":type encoding: :class:`str` or :data:`None`\n" ":param ns: the namespace prefix (optional)\n" - ":return: the pointer newly created node\n"; + ":type ns: :class:`str` or :data:`None`\n" + ":return: the pointer newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "method", "id", "type", "mime_type", "encoding", "ns", NULL}; @@ -590,11 +655,16 @@ static PyObject* PyXmlSec_TemplateCreateEncryptedData(PyObject* self, PyObject * } static char PyXmlSec_TemplateEncryptedDataEnsureKeyInfo__doc__[] = \ - "Adds <{ns}:KeyInfo/> to the node of *node*.\n\n" - ":param node: the pointer to node\n" - ":param id: the Id attribute (optional)\n" + "encrypted_data_ensure_key_info(node, id = None, ns = None) -> lxml.etree._Element\n" + "Adds :xml:`<{ns}:KeyInfo/>` to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":param id: the ``\"Id\"`` attribute (optional)\n" + ":type id: :class:`str` or :data:`None`\n" ":param ns: the namespace prefix (optional)\n" - ":return: the pointer to newly created node\n"; + ":type ns: :class:`str` or :data:`None`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "id", "ns", NULL}; @@ -630,9 +700,12 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureKeyInfo(PyObject* self, PyO } static char PyXmlSec_TemplateEncryptedDataEnsureCipherValue__doc__[] = \ - "Adds to the node of *node*.\n\n" - ":param node: the pointer to node\n" - ":return: the pointer to newly created node\n"; + "encrypted_data_ensure_cipher_value(node) -> lxml.etree._Element\n" + "Adds :xml:`` to the :xml:`` node of ``node``.\n\n" + ":param node: the pointer to :xml:`` node\n" + ":type node: :class:`lxml.etree._Element`\n" + ":return: the pointer to newly created :xml:`` node\n" + ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", NULL}; @@ -663,9 +736,12 @@ static PyObject* PyXmlSec_TemplateEncryptedDataEnsureCipherValue(PyObject* self, } static char PyXmlSec_TemplateTransformAddC14NInclNamespaces__doc__[] = \ - "Adds 'inclusive' namespaces to the ExcC14N transform node *node*.\n\n" - ":param node: the pointer to node.\n" - ":param prefixList: the list of namespace prefixes, where 'default' indicates the default namespace (optional)."; + "transform_add_c14n_inclusive_namespaces(node, prefixes = None) -> None\n" + "Adds 'inclusive' namespaces to the ExcC14N transform node ``node``.\n\n" + ":param node: the pointer to :xml:`` node.\n" + ":type node: :class:`lxml.etree._Element`\n" + ":param prefixes: the list of namespace prefixes, where ``'default'`` indicates the default namespace (optional).\n" + ":type prefixes: :class:`str` or :class:`list` of strings"; static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "prefixes", NULL}; diff --git a/src/tree.c b/src/tree.c index ac23b53f..34089a3b 100644 --- a/src/tree.c +++ b/src/tree.c @@ -16,11 +16,16 @@ #define PYXMLSEC_TREE_DOC "Common XML utility functions" static char PyXmlSec_TreeFindChild__doc__[] = \ - "Searches a direct child of the parent node having given name and namespace href.\n\n" + "find_child(parent, name, namespace)\n" + "Searches a direct child of the ``parent`` node having given ``name`` and ``namespace`` href.\n\n" ":param parent: the pointer to XML node\n" + ":type parent: :class:`lxml.etree._Element`\n" ":param name: the name\n" - ":param namespace: the namespace href(optional)\n" - ":return: the pointer to the found node or None if node is not found\n"; + ":type name: :class:`str`\n" + ":param namespace: the namespace href (optional)\n" + ":type namespace: :class:`str`\n" + ":return: the pointer to the found node or :data:`None` if node is not found\n" + ":rtype: :class:`lxml.etree._Element` or :data:`None`"; static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "parent", "name", "namespace", NULL}; @@ -52,11 +57,16 @@ static PyObject* PyXmlSec_TreeFindChild(PyObject* self, PyObject *args, PyObject } static char PyXmlSec_TreeFindParent__doc__[] = \ - "Searches the ancestors axis of the node having given name and namespace href.\n\n" + "find_parent(node, name, namespace)\n" + "Searches the ancestors axis of the ``node`` having given ``name`` and ``namespace`` href.\n\n" ":param node: the pointer to XML node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param name: the name\n" - ":param namespace: the namespace href(optional)\n" - ":return: the pointer to the found node or None if node is not found\n"; + ":type name: :class:`str`\n" + ":param namespace: the namespace href (optional)\n" + ":type namespace: :class:`str`\n" + ":return: the pointer to the found node or :data:`None` if node is not found\n" + ":rtype: :class:`lxml.etree._Element` or :data:`None`"; static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", "namespace", NULL}; @@ -88,11 +98,16 @@ static PyObject* PyXmlSec_TreeFindParent(PyObject* self, PyObject *args, PyObjec } static char PyXmlSec_TreeFindNode__doc__[] = \ - "Searches all children of the parent node having given name and namespace href.\n\n" + "find_node(node, name, namespace)\n" + "Searches all children of the given ``node`` having given ``name`` and ``namespace`` href.\n\n" ":param node: the pointer to XML node\n" + ":type node: :class:`lxml.etree._Element`\n" ":param name: the name\n" - ":param namespace: the namespace href(optional)\n" - ":return: the pointer to the found node or None if node is not found\n"; + ":type name: :class:`str`\n" + ":param namespace: the namespace href (optional)\n" + ":type namespace: :class:`str`\n" + ":return: the pointer to the found node or :data:`None` if node is not found\n" + ":rtype: :class:`lxml.etree._Element` or :data:`None`"; static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "name", "namespace", NULL}; @@ -124,10 +139,11 @@ static PyObject* PyXmlSec_TreeFindNode(PyObject* self, PyObject *args, PyObject } static char PyXmlSec_TreeAddIds__doc__[] = \ - "Registers *ids* as ids used below *node*. *ids* is a sequence of attribute names\n"\ - "used as XML ids in the subtree rooted at *node*.\n"\ - "A call to `addIds` may be necessary to make known which attributes contain XML ids.\n"\ - "This is the case, if a transform references an id via `XPointer` or a self document uri and\n" + "add_ids(node, ids) -> None\n" + "Registers ``ids`` as ids used below ``node``. ``ids`` is a sequence of attribute names "\ + "used as XML ids in the subtree rooted at ``node``.\n"\ + "A call to :func:`~.add_ids` may be necessary to make known which attributes contain XML ids.\n"\ + "This is the case, if a transform references an id via ``XPointer`` or a self document uri and " "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n\n" ":param node: the pointer to XML node\n" ":param ids: the list of ID attributes.\n"; From 81cadc50db1b703a96bc4f89a30d4d8d747defc3 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 9 May 2020 00:12:08 +0200 Subject: [PATCH 131/378] add crossref for lxml.etree._Element Signed-off-by: oleg.hoefling --- doc/source/conf.py | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index d03702ca..4f533230 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -17,8 +17,13 @@ # documentation root, use os.path.abspath to make it absolute, like shown here. # import sys +import urllib.request +import lxml + +from docutils.nodes import reference from packaging.version import parse +from sphinx.errors import ExtensionError # sys.path.insert(0, os.path.abspath('.')) @@ -172,8 +177,32 @@ intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} -nitpick_ignore = [ - # lxml doesn't have an intersphinx docs - # https://lxml.de/api/lxml.etree._Element-class.html - ('py:class', 'lxml.etree._Element') -] + +# LXML crossref'ing stuff: +# LXML doesn't have an intersphinx docs, +# so we link to lxml.etree._Element explicitly +lxml_element_cls_doc_uri = 'https://lxml.de/api/lxml.etree._Element-class.html' + + +def lxml_element_doc_reference(app, env, node, contnode): + """ + Handle a missing reference only if it is a ``lxml.etree._Element`` ref. + + We handle only :class:`lxml.etree._Element` and :class:`~lxml.etree._Element` nodes. + """ + if ( + node.get('reftype', None) == 'class' + and node.get('reftarget', None) == 'lxml.etree._Element' + and contnode.astext() in ('lxml.etree._Element', '_Element') + ): + reftitle = '(in lxml v{})'.format(lxml.__version__) + newnode = reference('', '', internal=False, refuri=lxml_element_cls_doc_uri, reftitle=reftitle) + newnode.append(contnode) + return newnode + + +def setup(app): + # first, check whether the doc URL is still valid + if urllib.request.urlopen(lxml_element_cls_doc_uri).getcode() != 200: + raise ExtensionError('URL to `lxml.etree._Element` docs is not accesible.') + app.connect('missing-reference', lxml_element_doc_reference) From d9f60d49c23eb3170b07c55f7bf8aa73aa8a2324 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 9 May 2020 01:36:34 +0200 Subject: [PATCH 132/378] enable inline xml code highlighting Signed-off-by: oleg.hoefling --- .travis.yml | 1 + doc/source/index.rst | 5 +++- doc/source/sphinx-pr-6916.diff | 46 ++++++++++++++++++++++++++++++++++ 3 files changed, 51 insertions(+), 1 deletion(-) create mode 100644 doc/source/sphinx-pr-6916.diff diff --git a/.travis.yml b/.travis.yml index b9cc5588..002c4b17 100644 --- a/.travis.yml +++ b/.travis.yml @@ -45,4 +45,5 @@ after_success: - codecov --file coverage.info before_deploy: - travis_retry pip install Sphinx importlib-metadata packaging +- git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff - sphinx-build -EWanb html doc/source build/sphinx diff --git a/doc/source/index.rst b/doc/source/index.rst index 6c3d313f..5cc758b9 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -1,7 +1,10 @@ .. python-xmlsec documentation master file, created by sphinx-quickstart on Fri Mar 17 10:30:14 2017. You can adapt this file completely to your liking, but it should at least - contain the root `toctree` directive. + contain the root ``toctree`` directive. + +.. role:: xml(code) + :language: xml Welcome to python-xmlsec's documentation! ========================================= diff --git a/doc/source/sphinx-pr-6916.diff b/doc/source/sphinx-pr-6916.diff new file mode 100644 index 00000000..e7040a0f --- /dev/null +++ b/doc/source/sphinx-pr-6916.diff @@ -0,0 +1,46 @@ +diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py +index bc9bf49a74..4804c89c52 100644 +--- a/sphinx/environment/__init__.py ++++ b/sphinx/environment/__init__.py +@@ -46,6 +46,7 @@ + default_settings = { + 'embed_stylesheet': False, + 'cloak_email_addresses': True, ++ 'syntax_highlight': 'short', + 'pep_base_url': 'https://www.python.org/dev/peps/', + 'pep_references': None, + 'rfc_base_url': 'https://tools.ietf.org/html/', +diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py +index 85eeb43..80f1eea 100644 +--- a/sphinx/writers/html.py ++++ b/sphinx/writers/html.py +@@ -494,8 +494,11 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): + self.body.append(self.starttag(node, 'kbd', '', + CLASS='docutils literal notranslate')) + else: ++ classes = 'docutils literal notranslate' ++ if 'code' in node['classes']: ++ classes += ' highlight' + self.body.append(self.starttag(node, 'code', '', +- CLASS='docutils literal notranslate')) ++ CLASS=classes)) + self.protect_literal_text += 1 + + def depart_literal(self, node: Element) -> None: +diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py +index 80cedd3..470f559 100644 +--- a/sphinx/writers/html5.py ++++ b/sphinx/writers/html5.py +@@ -446,8 +446,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): + self.body.append(self.starttag(node, 'kbd', '', + CLASS='docutils literal notranslate')) + else: ++ classes = 'docutils literal notranslate' ++ if 'code' in node['classes']: ++ classes += ' highlight' + self.body.append(self.starttag(node, 'code', '', +- CLASS='docutils literal notranslate')) ++ CLASS=classes)) + self.protect_literal_text += 1 + + def depart_literal(self, node: Element) -> None: From 52894df117abd15a1c7957756e39223ab794c1ad Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 9 May 2020 14:01:59 +0200 Subject: [PATCH 133/378] use rtd docs badge in readme Signed-off-by: oleg.hoefling --- README.rst | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/README.rst b/README.rst index e562a1ed..24c3f991 100644 --- a/README.rst +++ b/README.rst @@ -2,18 +2,18 @@ python-xmlsec ============= .. image:: https://travis-ci.org/mehcode/python-xmlsec.png?branch=master - :target: https://travis-ci.org/mehcode/python-xmlsec + :target: https://travis-ci.org/mehcode/python-xmlsec .. image:: https://ci.appveyor.com/api/projects/status/ij87xk5wo8a39jua?svg=true - :target: https://ci.appveyor.com/project/hoefling/xmlsec + :target: https://ci.appveyor.com/project/hoefling/xmlsec .. image:: https://github.com/mehcode/python-xmlsec/workflows/manylinux2010/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 + :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg - :target: https://codecov.io/gh/mehcode/python-xmlsec + :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg - :target: https://pypi.python.org/pypi/xmlsec -.. image:: https://img.shields.io/badge/docs-latest-green.svg - :target: http://pythonhosted.org/xmlsec/ - + :target: https://pypi.python.org/pypi/xmlsec +.. image:: https://readthedocs.org/projects/xmlsec/badge/?version=latest + :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest + :alt: Documentation Status Python bindings for the XML Security Library. From da4752829e8ab2f433b948970a6d4bbe778fd87a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 9 May 2020 15:54:08 +0200 Subject: [PATCH 134/378] add remaining types to docstrings Signed-off-by: oleg.hoefling --- src/constants.c | 78 ++++++++++++++++++++++++------------------------- src/ds.c | 14 +++++---- src/keys.c | 3 ++ src/template.c | 6 ++++ src/tree.c | 4 ++- 5 files changed, 59 insertions(+), 46 deletions(-) diff --git a/src/constants.c b/src/constants.c index e5947d1c..02f5250c 100644 --- a/src/constants.c +++ b/src/constants.c @@ -85,44 +85,44 @@ static PyGetSetDef PyXmlSec_TransformGetSet[] = { static PyTypeObject _PyXmlSec_TransformType = { PyVarObject_HEAD_INIT(NULL, 0) - STRINGIFY(MODULE_NAME) "constants.__Transform", /* tp_name */ - sizeof(PyXmlSec_Transform), /* tp_basicsize */ - 0, /* tp_itemsize */ - PyXmlSec_Transform__del__, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - PyXmlSec_Transform__repr__, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - PyXmlSec_Transform__str__, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - "The xmlSecTransformId reflection", /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - 0, /* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - PyXmlSec_TransformGetSet, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - 0, /* tp_init */ - 0, /* tp_alloc */ - 0, /* tp_new */ - 0, /* tp_free */ + STRINGIFY(MODULE_NAME) ".constants.__Transform", /* tp_name */ + sizeof(PyXmlSec_Transform), /* tp_basicsize */ + 0, /* tp_itemsize */ + PyXmlSec_Transform__del__, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_reserved */ + PyXmlSec_Transform__repr__, /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + PyXmlSec_Transform__str__, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + "The xmlSecTransformId reflection", /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + 0, /* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + PyXmlSec_TransformGetSet, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + 0, /* tp_init */ + 0, /* tp_alloc */ + 0, /* tp_new */ + 0, /* tp_free */ }; PyTypeObject* PyXmlSec_TransformType = &_PyXmlSec_TransformType; @@ -195,7 +195,7 @@ static PyGetSetDef PyXmlSec_KeyDataGetSet[] = { static PyTypeObject _PyXmlSec_KeyDataType = { PyVarObject_HEAD_INIT(NULL, 0) - STRINGIFY(MODULE_NAME) "constants.__KeyData", /* tp_name */ + STRINGIFY(MODULE_NAME) ".constants.__KeyData", /* tp_name */ sizeof(PyXmlSec_KeyData), /* tp_basicsize */ 0, /* tp_itemsize */ PyXmlSec_KeyData__del__, /* tp_dealloc */ diff --git a/src/ds.c b/src/ds.c index 44d046e0..43d3d118 100644 --- a/src/ds.c +++ b/src/ds.c @@ -301,7 +301,7 @@ static const char PyXmlSec_SignatureContextSignBinary__doc__[] = \ ":param bytes: the binary data\n" ":type bytes: :class:`bytes`\n" ":param transform: the signature algorithm\n" - ":type transform: :class:`Transform`\n" + ":type transform: :class:`__Transform`\n" ":return: the signature\n" ":rtype: :class:`bytes`"; static PyObject* PyXmlSec_SignatureContextSignBinary(PyObject* self, PyObject* args, PyObject* kwargs) { @@ -340,7 +340,7 @@ static const char PyXmlSec_SignatureContextVerifyBinary__doc__[] = \ ":param bytes: the binary data\n" ":type bytes: :class:`bytes`\n" ":param transform: the signature algorithm\n" - ":type transform: :class:`Transform`\n" + ":type transform: :class:`__Transform`\n" ":param signature: the signature\n" ":type signature: :class:`bytes`\n" ":return: :data:`None` on success\n" @@ -394,7 +394,8 @@ static const char PyXmlSec_SignatureContextEnableReferenceTransform__doc__[] = \ "Enables use of ``transform`` as reference transform.\n\n" ".. note:: by default, all transforms are enabled. The first call of " ":meth:`~SignatureContext.enable_reference_transform` will switch to explicitly enabled transforms.\n\n" - ":param transform: the transform klass.\n"; + ":param transform: the transform klass.\n" + ":type transform: :class:`__Transform`"; static PyObject* PyXmlSec_SignatureContextEnableReferenceTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -429,7 +430,8 @@ static const char PyXmlSec_SignatureContextEnableSignatureTransform__doc__[] = \ "Enables use of ``transform`` as signature transform.\n\n" ".. note:: by default, all transforms are enabled. The first call of " ":meth:`~SignatureContext.enable_signature_transform` will switch to explicitly enabled transforms.\n\n" - ":param transform: the transform klass.\n"; + ":param transform: the transform klass.\n" + ":type transform: :class:`__Transform`\n"; static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "transform", NULL}; @@ -460,9 +462,9 @@ static PyObject* PyXmlSec_SignatureContextEnableSignatureTransform(PyObject* sel static const char PyXmlSec_SignatureContextSetEnabledKeyData__doc__[] = \ "set_enabled_key_data(keydata_list) -> None\n" - "Adds selected :class:`KeyData` to the list of enabled key data list.\n\n" + "Adds selected :class:`__KeyData` to the list of enabled key data list.\n\n" ":param keydata_list: the list\n" - ":type keydata_list: :class:`list` of :class:`KeyData`"; + ":type keydata_list: :class:`list` of :class:`__KeyData`"; static PyObject* PyXmlSec_SignatureContextSetEnabledKeyData(PyObject* self, PyObject* args, PyObject* kwargs) { static char *kwlist[] = { "keydata_list", NULL}; diff --git a/src/keys.c b/src/keys.c index fadc875a..7fd080a1 100644 --- a/src/keys.c +++ b/src/keys.c @@ -189,6 +189,7 @@ static const char PyXmlSec_KeyGenerate__doc__[] = \ "generate(klass, size, type) -> xmlsec.Key\n" "Generates key of kind ``klass`` with ``size`` and ``type``.\n\n" ":param klass: the requested key klass (rsa, dsa, aes, ...)\n" + ":type klass: :class:`__KeyData`\n" ":param size: the new key size (in bits!)\n" ":type size: :class:`int`\n" ":param type: the new key type (session, permanent, ...)\n" @@ -232,6 +233,7 @@ static const char PyXmlSec_KeyFromBinaryFile__doc__[] = \ "from_binary_file(klass, filename) -> xmlsec.Key\n" "Loads (symmetric) key of kind ``klass`` from ``filename``.\n\n" ":param klass: the key value data klass\n" + ":type klass: :class:`__KeyData`\n" ":param filename: the key binary filename\n" ":type filename: :class:`str`, :class:`bytes` or any :class:`~os.PathLike`\n" ":return: pointer to newly created key\n" @@ -282,6 +284,7 @@ static const char PyXmlSec_KeyFromBinaryData__doc__[] = \ "from_binary_data(klass, data) -> xmlsec.Key\n" "Loads (symmetric) key of kind ``klass`` from ``data``.\n\n" ":param klass: the key value data klass\n" + ":type klass: :class:`__KeyData`\n" ":param data: the key binary data\n" ":type data: :class:`str` or :class:`bytes`\n" ":return: pointer to newly created key\n" diff --git a/src/template.c b/src/template.c index e38945b4..7d043606 100644 --- a/src/template.c +++ b/src/template.c @@ -24,7 +24,9 @@ static char PyXmlSec_TemplateCreate__doc__[] = \ ":param node: the signature node\n" ":type node: :class:`lxml.etree._Element`\n" ":param c14n_method: the signature canonicalization method\n" + ":type c14n_method: :class:`__Transform`\n" ":param sign_method: the signature method\n" + ":type sign_method: :class:`__Transform`\n" ":param id: the node id (optional)\n" ":type id: :class:`str` or :data:`None`\n" ":param ns: the namespace prefix for the signature element (e.g. ``\"dsig\"``) (optional)\n" @@ -71,6 +73,7 @@ static char PyXmlSec_TemplateAddReference__doc__[] = \ ":param node: the pointer to :xml:`` node\n" ":type node: :class:`lxml.etree._Element`\n" ":param digest_method: the reference digest method\n" + ":type digest_method: :class:`__Transform`\n" ":param id: the node id (optional)\n" ":type id: :class:`str` or :data:`None`\n" ":param uri: the reference node URI (optional)\n" @@ -117,6 +120,7 @@ static char PyXmlSec_TemplateAddTransform__doc__[] = \ ":param node: the pointer to :xml:`` node\n" ":type node: :class:`lxml.etree._Element`\n" ":param transform: the transform method id\n" + ":type transform: :class:`__Transform`\n" ":return: the pointer to newly created :xml:`` node\n" ":rtype: :class:`lxml.etree._Element`"; static PyObject* PyXmlSec_TemplateAddTransform(PyObject* self, PyObject *args, PyObject *kwargs) { @@ -557,6 +561,7 @@ static char PyXmlSec_TemplateAddEncryptedKey__doc__[] = \ ":param node: the pointer to :xml:`` node\n" ":type node: :class:`lxml.etree._Element`\n" ":param method: the encryption method\n" + ":type method: :class:`__Transform`\n" ":param id: the ``\"Id\"`` attribute (optional)\n" ":type id: :class:`str` or :data:`None`\n" ":param type: the ``\"Type\"`` attribute (optional)\n" @@ -604,6 +609,7 @@ static char PyXmlSec_TemplateCreateEncryptedData__doc__[] = \ ":param node: the pointer to signature node\n" ":type node: :class:`lxml.etree._Element`\n" ":param method: the encryption method\n" + ":type method: :class:`__Transform`\n" ":param id: the ``\"Id\"`` attribute (optional)\n" ":type id: :class:`str` or :data:`None`\n" ":param type: the ``\"Type\"`` attribute (optional)\n" diff --git a/src/tree.c b/src/tree.c index 34089a3b..76037d3b 100644 --- a/src/tree.c +++ b/src/tree.c @@ -146,7 +146,9 @@ static char PyXmlSec_TreeAddIds__doc__[] = \ "This is the case, if a transform references an id via ``XPointer`` or a self document uri and " "the id inkey_data_formation is not available by other means (e.g. an associated DTD or XML schema).\n\n" ":param node: the pointer to XML node\n" - ":param ids: the list of ID attributes.\n"; + ":type node: :class:`lxml.etree._Element`\n" + ":param ids: the list of ID attributes.\n" + ":type ids: :class:`list` of strings"; static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "node", "ids", NULL}; From 61c5bed565fb4ce2ca46ae55a1d6f05830f5c2b4 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 9 May 2020 15:55:58 +0200 Subject: [PATCH 135/378] rework docs for xmlsec.constants module Signed-off-by: oleg.hoefling --- doc/source/modules/constants.rst | 599 ++++++++++++++++++++++++------- doc/source/modules/template.rst | 4 +- doc/source/modules/tree.rst | 4 +- doc/source/modules/xmlsec.rst | 4 +- 4 files changed, 477 insertions(+), 134 deletions(-) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 67f2d711..4a63fcd7 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -1,154 +1,497 @@ -xmlsec.constants ----------------- +``xmlsec.constants`` +-------------------- -Various constants used by the library +Various constants used by the library. EncryptionType ************** -- *TypeEncContent* - http://www.w3.org/2001/04/xmlenc#Content -- *TypeEncElement* - http://www.w3.org/2001/04/xmlenc#Element + +.. data:: xmlsec.constants.TypeEncContent + :annotation: = 'http://www.w3.org/2001/04/xmlenc#Content' + +.. data:: xmlsec.constants.TypeEncElement + :annotation: = 'http://www.w3.org/2001/04/xmlenc#Element' KeyData ******* -- *KeyDataName* - The processing class. -- *KeyDataValue* - The processing class. -- *KeyDataRetrievalMethod* - The processing class. -- *KeyDataEncryptedKey* - The processing class. -- *KeyDataAes* - The AES key klass. -- *KeyDataDes* - The DES key klass. -- *KeyDataDsa* - The DSA key klass. -- *KeyDataEcdsa* - The ECDSA key klass. -- *KeyDataHmac* - The DHMAC key klass. -- *KeyDataRsa* - The RSA key klass. -- *KeyDataX509* - The X509 data klass. -- *KeyDataRawX509Cert* - The raw X509 certificate klass. + +.. class:: __KeyData + + Base type for all :samp:`KeyData{XXX}` constants. + +.. data:: xmlsec.constants.KeyDataName + + The :xml:`` processing class. + +.. data:: xmlsec.constants.KeyDataValue + + The :xml:`` processing class. + +.. data:: xmlsec.constants.KeyDataRetrievalMethod + + The :xml:`` processing class. + +.. data:: xmlsec.constants.KeyDataEncryptedKey + + The :xml:`` processing class. + +.. data:: xmlsec.constants.KeyDataAes + + The AES key klass. + +.. data:: xmlsec.constants.KeyDataDes + + The DES key klass. + +.. data:: xmlsec.constants.KeyDataDsa + + The DSA key klass. + +.. data:: xmlsec.constants.KeyDataEcdsa + + The ECDSA key klass. + +.. data:: xmlsec.constants.KeyDataHmac + + The DHMAC key klass. + +.. data:: xmlsec.constants.KeyDataRsa + + The RSA key klass. + +.. data:: xmlsec.constants.KeyDataX509 + + The X509 data klass. + +.. data:: xmlsec.constants.KeyDataRawX509Cert + + The raw X509 certificate klass. KeyDataFormat ************* -- *KeyDataFormatUnknown* - the key data format is unknown. -- *KeyDataFormatBinary* - the binary key data. -- *KeyDataFormatPem* - the PEM key data (cert or public/private key). -- *KeyDataFormatDer* - the DER key data (cert or public/private key). -- *KeyDataFormatPkcs8Pem* - the PKCS8 PEM private key. -- *KeyDataFormatPkcs8Der* - the PKCS8 DER private key. -- *KeyDataFormatPkcs12* - the PKCS12 format (bag of keys and certs) -- *KeyDataFormatCertPem* - the PEM cert. -- *KeyDataFormatCertDer* - the DER cert. + +.. data:: xmlsec.constants.KeyDataFormatUnknown + + the key data format is unknown. + +.. data:: xmlsec.constants.KeyDataFormatBinary + + the binary key data. + +.. data:: xmlsec.constants.KeyDataFormatPem + + the PEM key data (cert or public/private key). + +.. data:: xmlsec.constants.KeyDataFormatDer + + the DER key data (cert or public/private key). + +.. data:: xmlsec.constants.KeyDataFormatPkcs8Pem + + the PKCS8 PEM private key. + +.. data:: xmlsec.constants.KeyDataFormatPkcs8Der + + the PKCS8 DER private key. + +.. data:: xmlsec.constants.KeyDataFormatPkcs12 + + the PKCS12 format (bag of keys and certs) + +.. data:: xmlsec.constants.KeyDataFormatCertPem + + the PEM cert. + +.. data:: xmlsec.constants.KeyDataFormatCertDer + + the DER cert. KeyDataType *********** -- *KeyDataTypeUnknown* - The key data type is unknown -- *KeyDataTypeNone* - The key data type is unknown -- *KeyDataTypePublic* - The key data contain a public key. -- *KeyDataTypePrivate* - The key data contain a private key. -- *KeyDataTypeSymmetric* - The key data contain a symmetric key. -- *KeyDataTypeSession* - The key data contain session key (one time key, not stored in keys manager). -- *KeyDataTypePermanent* - The key data contain permanent key (stored in keys manager). -- *KeyDataTypeTrusted* - The key data is trusted. -- *KeyDataTypeAny* - The key data is trusted. + +.. data:: xmlsec.constants.KeyDataTypeUnknown + + The key data type is unknown + +.. data:: xmlsec.constants.KeyDataTypeNone + + The key data type is unknown + +.. data:: xmlsec.constants.KeyDataTypePublic + + The key data contain a public key. + +.. data:: xmlsec.constants.KeyDataTypePrivate + + The key data contain a private key. + +.. data:: xmlsec.constants.KeyDataTypeSymmetric + + The key data contain a symmetric key. + +.. data:: xmlsec.constants.KeyDataTypeSession + + The key data contain session key (one time key, not stored in keys manager). + +.. data:: xmlsec.constants.KeyDataTypePermanent + + The key data contain permanent key (stored in keys manager). + +.. data:: xmlsec.constants.KeyDataTypeTrusted + + The key data is trusted. + +.. data:: xmlsec.constants.KeyDataTypeAny + + The key data is trusted. Namespaces ********** -- *Ns* - http://www.aleksey.com/xmlsec/2002 -- *DSigNs* - http://www.w3.org/2000/09/xmldsig# -- *EncNs* - http://www.w3.org/2001/04/xmlenc# -- *XPathNs* - http://www.w3.org/TR/1999/REC-xpath-19991116 -- *XPath2Ns* - http://www.w3.org/2002/06/xmldsig-filter2 -- *XPointerNs* - http://www.w3.org/2001/04/xmldsig-more/xptr -- *Soap11Ns* - http://schemas.xmlsoap.org/soap/envelope/ -- *Soap12Ns* - http://www.w3.org/2002/06/soap-envelope -- *NsExcC14N* - http://www.w3.org/2001/10/xml-exc-c14n# -- *NsExcC14NWithComments* - http://www.w3.org/2001/10/xml-exc-c14n#WithComments +.. data:: xmlsec.constants.Ns + :annotation: = 'http://www.aleksey.com/xmlsec/2002' + +.. data:: xmlsec.constants.DSigNs + :annotation: = 'http://www.w3.org/2000/09/xmldsig#' + +.. data:: xmlsec.constants.EncNs + :annotation: = 'http://www.w3.org/2001/04/xmlenc#' + +.. data:: xmlsec.constants.XPathNs + :annotation: = 'http://www.w3.org/TR/1999/REC-xpath-19991116' + +.. data:: xmlsec.constants.XPath2Ns + :annotation: = 'http://www.w3.org/2002/06/xmldsig-filter2' + +.. data:: xmlsec.constants.XPointerNs + :annotation: = 'http://www.w3.org/2001/04/xmldsig-more/xptr' + +.. data:: xmlsec.constants.Soap11Ns + :annotation: = 'http://schemas.xmlsoap.org/soap/envelope/' + +.. data:: xmlsec.constants.Soap12Ns + :annotation: = 'http://www.w3.org/2002/06/soap-envelope' + +.. data:: xmlsec.constants.NsExcC14N + :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#' + +.. data:: xmlsec.constants.NsExcC14NWithComments + :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' Nodes ***** -- *NodeSignature* - Signature -- *NodeSignedInfo* - SignedInfo -- *NodeCanonicalizationMethod* - CanonicalizationMethod -- *NodeSignatureMethod* - SignatureMethod -- *NodeSignatureValue* - SignatureValue -- *NodeSignatureProperties* - SignatureProperties -- *NodeDigestMethod* - DigestMethod -- *NodeDigestValue* - DigestValue -- *NodeObject* - Object -- *NodeManifest* - Manifest -- *NodeEncryptedData* - EncryptedData -- *NodeEncryptedKey* - EncryptedKey -- *NodeEncryptionMethod* - EncryptionMethod -- *NodeEncryptionProperties* - EncryptionProperties -- *NodeEncryptionProperty* - EncryptionProperty -- *NodeCipherData* - CipherData -- *NodeCipherValue* - CipherValue -- *NodeCipherReference* - CipherReference -- *NodeReference - Reference -- *NodeReferenceList* - ReferenceList -- *NodeDataReference* - DataReference -- *NodeKeyReference* - KeyReference -- *NodeKeyInfo* - KeyInfo -- *NodeKeyName - KeyName -- *NodeKeyValue - KeyValue -- *NodeX509Data - X509Data + +.. data:: xmlsec.constants.NodeSignature + :annotation: = 'Signature' + +.. data:: xmlsec.constants.NodeSignedInfo + :annotation: = 'SignedInfo' + +.. data:: xmlsec.constants.NodeCanonicalizationMethod + :annotation: = 'CanonicalizationMethod' + +.. data:: xmlsec.constants.NodeSignatureMethod + :annotation: = 'SignatureMethod' + +.. data:: xmlsec.constants.NodeSignatureValue + :annotation: = 'SignatureValue' + +.. data:: xmlsec.constants.NodeSignatureProperties + :annotation: = 'SignatureProperties' + +.. data:: xmlsec.constants.NodeDigestMethod + :annotation: = 'DigestMethod' + +.. data:: xmlsec.constants.NodeDigestValue + :annotation: = 'DigestValue' + +.. data:: xmlsec.constants.NodeObject + :annotation: = 'Object' + +.. data:: xmlsec.constants.NodeManifest + :annotation: = 'Manifest' + +.. data:: xmlsec.constants.NodeEncryptedData + :annotation: = 'EncryptedData' + +.. data:: xmlsec.constants.NodeEncryptedKey + :annotation: = 'EncryptedKey' + +.. data:: xmlsec.constants.NodeEncryptionMethod + :annotation: = 'EncryptionMethod' + +.. data:: xmlsec.constants.NodeEncryptionProperties + :annotation: = 'EncryptionProperties' + +.. data:: xmlsec.constants.NodeEncryptionProperty + :annotation: = 'EncryptionProperty' + +.. data:: xmlsec.constants.NodeCipherData + :annotation: = 'CipherData' + +.. data:: xmlsec.constants.NodeCipherValue + :annotation: = 'CipherValue' + +.. data:: xmlsec.constants.NodeCipherReference + :annotation: = 'CipherReference' + +.. data:: xmlsec.constants.NodeReference + :annotation: = 'Reference' + +.. data:: xmlsec.constants.NodeReferenceList + :annotation: = 'ReferenceList' + +.. data:: xmlsec.constants.NodeDataReference + :annotation: = 'DataReference' + +.. data:: xmlsec.constants.NodeKeyReference + :annotation: = 'KeyReference' + +.. data:: xmlsec.constants.NodeKeyInfo + :annotation: = 'KeyInfo' + +.. data:: xmlsec.constants.NodeKeyName + :annotation: = 'KeyName' + +.. data:: xmlsec.constants.NodeKeyValue + :annotation: = 'KeyValue' + +.. data:: xmlsec.constants.NodeX509Data + :annotation: = 'X509Data' Transforms ********** -- *TransformUsageUnknown* - Transforms usage is unknown or undefined. -- *TransformUsageDSigTransform* - Transform could be used in . -- *TransformUsageC14NMethod* - Transform could be used in . -- *TransformUsageDigestMethod* - Transform could be used in . -- *TransformUsageSignatureMethod* - Transform could be used in . -- *TransformUsageEncryptionMethod* - Transform could be used in . -- *TransformUsageAny* - Transform could be used for operation. -- *TransformInclC14N* - The regular (inclusive) C14N without comments transform klass. -- *TransformInclC14NWithComments* - The regular (inclusive) C14N with comments transform klass. -- *TransformInclC14N11* - The regular (inclusive) C14N 1.1 without comments transform klass. -- *TransformInclC14N11WithComments* - The regular (inclusive) C14N 1.1 with comments transform klass. -- *TransformExclC14N* - The exclusive C14N without comments transform klass. -- *TransformExclC14NWithComments* - The exclusive C14N with comments transform klass. -- *TransformEnveloped* - The "enveloped" transform klass. -- *TransformXPath* - The XPath transform klass. -- *TransformXPath2* - The XPath2 transform klass. -- *TransformXPointer* - The XPointer transform klass. -- *TransformXslt* - The XSLT transform klass. -- *TransformRemoveXmlTagsC14N* - The "remove all xml tags" transform klass (used before base64 transforms). -- *TransformVisa3DHack* - Selects node subtree by given node id string. The only reason why we need this is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows invalid XPointer expressions in the URI attribute. Since we couldn't evaluate such expressions thru XPath/XPointer engine, we need to have this hack here. -- *TransformAes128Cbc* - The AES128 CBC cipher transform klass. -- *TransformAes192Cbc* - The AES192 CBC cipher transform klass. -- *TransformAes256Cbc* - The AES256 CBC cipher transform klass. -- *TransformKWAes128* - The AES 128 key wrap transform klass. -- *TransformKWAes192* - The AES 192 key wrap transform klass. -- *TransformKWAes256* - The AES 256 key wrap transform klass. -- *TransformDes3Cbc* - The DES3 CBC cipher transform klass. -- *TransformKWDes3* - The DES3 key wrap transform klass. -- *TransformDsaSha1* - The DSA-SHA1 signature transform klass. -- *TransformEcdsaSha1* - The ECDSA-SHA1 signature transform klass. -- *TransformEcdsaSha224* - The ECDSA-SHA224 signature transform klass. -- *TransformEcdsaSha256* - The ECDSA-SHA256 signature transform klass. -- *TransformEcdsaSha384* - The ECDS-SHA384 signature transform klass. -- *TransformEcdsaSha512* - The ECDSA-SHA512 signature transform klass. -- *TransformHmacMd5* - The HMAC with MD5 signature transform klass. -- *TransformHmacRipemd160* - The HMAC with RipeMD160 signature transform klass. -- *TransformHmacSha1* - The HMAC with SHA1 signature transform klass. -- *TransformHmacSha224* - The HMAC with SHA224 signature transform klass. -- *TransformHmacSha256* - The HMAC with SHA256 signature transform klass. -- *TransformHmacSha384* - The HMAC with SHA384 signature transform klass. -- *TransformHmacSha512* - The HMAC with SHA512 signature transform klass. -- *TransformRsaMd5* - The RSA-MD5 signature transform klass. -- *TransformRsaRipemd160* - The RSA-RIPEMD160 signature transform klass. -- *TransformRsaSha1* - The RSA-SHA1 signature transform klass. -- *TransformRsaSha224* - The RSA-SHA224 signature transform klass. -- *TransformRsaSha256* - The RSA-SHA256 signature transform klass. -- *TransformRsaSha384* - The RSA-SHA384 signature transform klass. -- *TransformRsaSha512* - The RSA-SHA512 signature transform klass. -- *TransformRsaPkcs1* - The RSA PKCS1 key transport transform klass. -- *TransformRsaOaep* - The RSA OAEP key transport transform klass. -- *TransformMd5* - The MD5 digest transform klass. -- *TransformRipemd160* - The RIPEMD160 digest transform klass. -- *TransformSha1* - The SHA1 digest transform klass. -- *TransformSha224* - The SHA224 digest transform klass. -- *TransformSha256* - The SHA256 digest transform klass. -- *TransformSha384* - The SHA384 digest transform klass. -- *TransformSha512* - The SHA512 digest transform klass. +.. class:: __Transform + + Base type for all :samp:`Transform{XXX}` constants. + +.. data:: xmlsec.constants.TransformUsageUnknown + + Transforms usage is unknown or undefined. + +.. data:: xmlsec.constants.TransformUsageDSigTransform + + Transform could be used in :xml:``. + +.. data:: xmlsec.constants.TransformUsageC14NMethod + + Transform could be used in :xml:``. + +.. data:: xmlsec.constants.TransformUsageDigestMethod + + Transform could be used in :xml:``. + +.. data:: xmlsec.constants.TransformUsageSignatureMethod + + Transform could be used in :xml:``. + +.. data:: xmlsec.constants.TransformUsageEncryptionMethod + + Transform could be used in :xml:``. + +.. data:: xmlsec.constants.TransformUsageAny + + Transform could be used for operation. + +.. data:: xmlsec.constants.TransformInclC14N + + The regular (inclusive) C14N without comments transform klass. + +.. data:: xmlsec.constants.TransformInclC14NWithComments + + The regular (inclusive) C14N with comments transform klass. + +.. data:: xmlsec.constants.TransformInclC14N11 + + The regular (inclusive) C14N 1.1 without comments transform klass. + +.. data:: xmlsec.constants.TransformInclC14N11WithComments + + The regular (inclusive) C14N 1.1 with comments transform klass. + +.. data:: xmlsec.constants.TransformExclC14N + + The exclusive C14N without comments transform klass. + +.. data:: xmlsec.constants.TransformExclC14NWithComments + + The exclusive C14N with comments transform klass. + +.. data:: xmlsec.constants.TransformEnveloped + + The "enveloped" transform klass. + +.. data:: xmlsec.constants.TransformXPath + + The XPath transform klass. + +.. data:: xmlsec.constants.TransformXPath2 + + The XPath2 transform klass. + +.. data:: xmlsec.constants.TransformXPointer + + The XPointer transform klass. + +.. data:: xmlsec.constants.TransformXslt + + The XSLT transform klass. + +.. data:: xmlsec.constants.TransformRemoveXmlTagsC14N + + The "remove all xml tags" transform klass (used before base64 transforms). + +.. data:: xmlsec.constants.TransformVisa3DHack + + Selects node subtree by given node id string. The only reason why we need this is Visa3D protocol. It doesn't follow XML/XPointer/XMLDSig specs and allows invalid XPointer expressions in the URI attribute. Since we couldn't evaluate such expressions thru XPath/XPointer engine, we need to have this hack here. + +.. data:: xmlsec.constants.TransformAes128Cbc + + The AES128 CBC cipher transform klass. + +.. data:: xmlsec.constants.TransformAes192Cbc + + The AES192 CBC cipher transform klass. + +.. data:: xmlsec.constants.TransformAes256Cbc + + The AES256 CBC cipher transform klass. + +.. data:: xmlsec.constants.TransformKWAes128 + + The AES 128 key wrap transform klass. + +.. data:: xmlsec.constants.TransformKWAes192 + + The AES 192 key wrap transform klass. + +.. data:: xmlsec.constants.TransformKWAes256 + + The AES 256 key wrap transform klass. + +.. data:: xmlsec.constants.TransformDes3Cbc + + The DES3 CBC cipher transform klass. + +.. data:: xmlsec.constants.TransformKWDes3 + + The DES3 key wrap transform klass. + +.. data:: xmlsec.constants.TransformDsaSha1 + + The DSA-SHA1 signature transform klass. + +.. data:: xmlsec.constants.TransformEcdsaSha1 + + The ECDSA-SHA1 signature transform klass. + +.. data:: xmlsec.constants.TransformEcdsaSha224 + + The ECDSA-SHA224 signature transform klass. + +.. data:: xmlsec.constants.TransformEcdsaSha256 + + The ECDSA-SHA256 signature transform klass. + +.. data:: xmlsec.constants.TransformEcdsaSha384 + + The ECDS-SHA384 signature transform klass. + +.. data:: xmlsec.constants.TransformEcdsaSha512 + + The ECDSA-SHA512 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacMd5 + + The HMAC with MD5 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacRipemd160 + + The HMAC with RipeMD160 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacSha1 + + The HMAC with SHA1 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacSha224 + + The HMAC with SHA224 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacSha256 + + The HMAC with SHA256 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacSha384 + + The HMAC with SHA384 signature transform klass. + +.. data:: xmlsec.constants.TransformHmacSha512 + + The HMAC with SHA512 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaMd5 + + The RSA-MD5 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaRipemd160 + + The RSA-RIPEMD160 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaSha1 + + The RSA-SHA1 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaSha224 + + The RSA-SHA224 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaSha256 + + The RSA-SHA256 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaSha384 + + The RSA-SHA384 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaSha512 + + The RSA-SHA512 signature transform klass. + +.. data:: xmlsec.constants.TransformRsaPkcs1 + + The RSA PKCS1 key transport transform klass. + +.. data:: xmlsec.constants.TransformRsaOaep + + The RSA OAEP key transport transform klass. + +.. data:: xmlsec.constants.TransformMd5 + + The MD5 digest transform klass. + +.. data:: xmlsec.constants.TransformRipemd160 + + The RIPEMD160 digest transform klass. + +.. data:: xmlsec.constants.TransformSha1 + + The SHA1 digest transform klass. + +.. data:: xmlsec.constants.TransformSha224 + + The SHA224 digest transform klass. + +.. data:: xmlsec.constants.TransformSha256 + + The SHA256 digest transform klass. + +.. data:: xmlsec.constants.TransformSha384 + + The SHA384 digest transform klass. + +.. data:: xmlsec.constants.TransformSha512 + + The SHA512 digest transform klass. :ref:`contents` diff --git a/doc/source/modules/template.rst b/doc/source/modules/template.rst index c1e4b762..85551d2a 100644 --- a/doc/source/modules/template.rst +++ b/doc/source/modules/template.rst @@ -1,5 +1,5 @@ -xmlsec.template ---------------- +``xmlsec.template`` +------------------- .. automodule:: xmlsec.template :members: diff --git a/doc/source/modules/tree.rst b/doc/source/modules/tree.rst index 0dd70ea4..e70d6509 100644 --- a/doc/source/modules/tree.rst +++ b/doc/source/modules/tree.rst @@ -1,5 +1,5 @@ -xmlsec.tree ------------ +``xmlsec.tree`` +--------------- .. automodule:: xmlsec.tree :members: diff --git a/doc/source/modules/xmlsec.rst b/doc/source/modules/xmlsec.rst index 35a16339..426bbaa4 100644 --- a/doc/source/modules/xmlsec.rst +++ b/doc/source/modules/xmlsec.rst @@ -1,5 +1,5 @@ -xmlsec ------- +``xmlsec`` +---------- .. automodule:: xmlsec :members: From ad3aa2177227fd933a428728d3987477c64af9ae Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 13:42:28 +0200 Subject: [PATCH 136/378] record additional packages for doc build in requirements file Signed-off-by: oleg.hoefling --- .travis.yml | 2 +- doc/source/requirements.txt | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 doc/source/requirements.txt diff --git a/.travis.yml b/.travis.yml index 002c4b17..b5738884 100644 --- a/.travis.yml +++ b/.travis.yml @@ -44,6 +44,6 @@ after_success: - lcov --list coverage.info - codecov --file coverage.info before_deploy: -- travis_retry pip install Sphinx importlib-metadata packaging +- travis_retry pip install Sphinx -r doc/source/requirements.txt - git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff - sphinx-build -EWanb html doc/source build/sphinx diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt new file mode 100644 index 00000000..57d21954 --- /dev/null +++ b/doc/source/requirements.txt @@ -0,0 +1,2 @@ +importlib_metadata;python_version < '3.8' +packaging From 37f314fb37f6be923841301c314ce55509135cb4 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 13:50:43 +0200 Subject: [PATCH 137/378] add rtd config Signed-off-by: oleg.hoefling --- .gitignore | 1 + .readthedocs.yml | 9 +++++++++ 2 files changed, 10 insertions(+) create mode 100644 .readthedocs.yml diff --git a/.gitignore b/.gitignore index be6e8c15..1ef359b3 100644 --- a/.gitignore +++ b/.gitignore @@ -4,6 +4,7 @@ !.travis* !.appveyor* !.git* +!.readthedocs.yml # Python /dist diff --git a/.readthedocs.yml b/.readthedocs.yml new file mode 100644 index 00000000..6df6dfd9 --- /dev/null +++ b/.readthedocs.yml @@ -0,0 +1,9 @@ +version: 2 + +sphinx: + configuration: doc/source/conf.py + +python: + version: 3.7 + install: + - requirements: doc/source/requirements.txt From 694aefd5e6b0d0ae751b9f9fb3c692fa768868aa Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 13:56:29 +0200 Subject: [PATCH 138/378] add lxml to doc requirements Signed-off-by: oleg.hoefling --- doc/source/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt index 57d21954..19253133 100644 --- a/doc/source/requirements.txt +++ b/doc/source/requirements.txt @@ -1,2 +1,3 @@ +lxml>=3.8 importlib_metadata;python_version < '3.8' packaging From a499e4d8daefd894bf699d110cc63d801208797d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 14:18:47 +0200 Subject: [PATCH 139/378] install xmlsec when building docs Signed-off-by: oleg.hoefling --- .readthedocs.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.readthedocs.yml b/.readthedocs.yml index 6df6dfd9..4d8647be 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -6,4 +6,6 @@ sphinx: python: version: 3.7 install: + - method: pip + path: . - requirements: doc/source/requirements.txt From 3cf7a19d11ddce41d51f28ef7bee33851c52e08f Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 23:27:18 +0200 Subject: [PATCH 140/378] force latest sphinx version Signed-off-by: oleg.hoefling --- doc/source/requirements.txt | 1 + 1 file changed, 1 insertion(+) diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt index 19253133..09ff0002 100644 --- a/doc/source/requirements.txt +++ b/doc/source/requirements.txt @@ -1,3 +1,4 @@ lxml>=3.8 importlib_metadata;python_version < '3.8' packaging +Sphinx>=3 From 45f812af18a2c3fdbf1411c5d2eef0e124409991 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 20 May 2020 22:21:49 +0200 Subject: [PATCH 141/378] remove sphinx boilerplate from conf, bump copyright Signed-off-by: oleg.hoefling --- doc/source/conf.py | 121 ++------------------------------------------- 1 file changed, 5 insertions(+), 116 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 4f533230..bb75403b 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,21 +1,5 @@ # -*- coding: utf-8 -*- -# -# python-xmlsec documentation build configuration file, created by -# sphinx-quickstart on Fri Mar 17 10:30:14 2017. -# -# This file is execfile()d with the current directory set to its -# containing dir. -# -# Note that not all possible configuration values are present in this -# autogenerated file. -# -# All configuration values have a default; values that are commented out -# serve to show the default. - -# If extensions (or modules to document with autodoc) are in another directory, -# add these directories to sys.path here. If the directory is relative to the -# documentation root, use os.path.abspath to make it absolute, like shown here. -# + import sys import urllib.request @@ -25,117 +9,37 @@ from packaging.version import parse from sphinx.errors import ExtensionError -# sys.path.insert(0, os.path.abspath('.')) - - if sys.version_info >= (3, 8): from importlib import metadata as importlib_metadata else: import importlib_metadata -# -- General configuration ------------------------------------------------ - -# If your documentation needs a minimal Sphinx version, state it here. -# -# needs_sphinx = '1.0' - -# Add any Sphinx extension module names here, as strings. They can be -# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom -# ones. extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] -# Add any paths that contain templates here, relative to this directory. -templates_path = ['_templates'] +intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} -# The suffix(es) of source filenames. -# You can specify multiple suffix as a list of string: -# -# source_suffix = ['.rst', '.md'] +templates_path = ['_templates'] source_suffix = '.rst' - -# The master toctree document. master_doc = 'index' -# General information about the project. project = u'python-xmlsec' -copyright = u'2017, Bulat Gaifullin ' +copyright = u'2020, Oleg Hoefling ' author = u'Bulat Gaifullin ' - -# The version info for the project you're documenting, acts as replacement for -# |version| and |release|, also used in various other places throughout the -# built documents. -# -# The full version, including alpha/beta/rc tags. release = importlib_metadata.version('xmlsec') -# The short X.Y version. parsed = parse(release) version = '{}.{}'.format(parsed.major, parsed.minor) -# The language for content autogenerated by Sphinx. Refer to documentation -# for a list of supported languages. -# -# This is also used if you do content translation via gettext catalogs. -# Usually you set "language" from the command line for these cases. language = None - -# List of patterns, relative to source directory, that match files and -# directories to ignore when looking for source files. -# This patterns also effect to html_static_path and html_extra_path exclude_patterns = [] - -# The name of the Pygments (syntax highlighting) style to use. pygments_style = 'sphinx' - -# If true, `todo` and `todoList` produce output, else they produce nothing. todo_include_todos = False - -# -- Options for HTML output ---------------------------------------------- - -# The theme to use for HTML and HTML Help pages. See the documentation for -# a list of builtin themes. -# html_theme = 'nature' - -# Theme options are theme-specific and customize the look and feel of a theme -# further. For a list of options available for each theme, see the -# documentation. -# -# html_theme_options = {} - -# Add any paths that contain custom static files (such as style sheets) here, -# relative to this directory. They are copied after the builtin static files, -# so a file named "default.css" will overwrite the builtin "default.css". html_static_path = [] - - -# -- Options for HTMLHelp output ------------------------------------------ - -# Output file base name for HTML help builder. htmlhelp_basename = 'python-xmlsecdoc' - -# -- Options for LaTeX output --------------------------------------------- - -latex_elements = { - # The paper size ('letterpaper' or 'a4paper'). - # - # 'papersize': 'letterpaper', - # The font size ('10pt', '11pt' or '12pt'). - # - # 'pointsize': '10pt', - # Additional stuff for the LaTeX preamble. - # - # 'preamble': '', - # Latex figure (float) alignment - # - # 'figure_align': 'htbp', -} - -# Grouping the document tree into LaTeX files. List of tuples -# (source start file, target name, title, -# author, documentclass [howto, manual, or own class]). +latex_elements = {} latex_documents = [ ( master_doc, @@ -146,19 +50,8 @@ ) ] - -# -- Options for manual page output --------------------------------------- - -# One entry per manual page. List of tuples -# (source start file, name, description, authors, manual section). man_pages = [(master_doc, 'python-xmlsec', u'python-xmlsec Documentation', [author], 1)] - -# -- Options for Texinfo output ------------------------------------------- - -# Grouping the document tree into Texinfo files. List of tuples -# (source start file, target name, title, author, -# dir menu entry, description, category) texinfo_documents = [ ( master_doc, @@ -172,12 +65,8 @@ ] autodoc_member_order = 'groupwise' - autodoc_docstring_signature = True -intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} - - # LXML crossref'ing stuff: # LXML doesn't have an intersphinx docs, # so we link to lxml.etree._Element explicitly From 777b6e2de9774665609b50f38274420ecf7efcda Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 6 May 2020 20:31:24 +0200 Subject: [PATCH 142/378] add stubs for xmlsec package Signed-off-by: oleg.hoefling --- src/xmlsec/__init__.pyi | 72 +++++++++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 src/xmlsec/__init__.pyi diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi new file mode 100644 index 00000000..5c2edd74 --- /dev/null +++ b/src/xmlsec/__init__.pyi @@ -0,0 +1,72 @@ +import sys +from typing import AnyStr, Iterable, Optional, Type, TypeVar, Union + +from lxml.etree import _Element + +from xmlsec.constants import __KeyData as KeyData, __Transform as Transform + +if sys.version_info >= (3, 6): + from os import PathLike + from pathlib import PurePath + + _Path = Union[str, bytes, PurePath, PathLike[str], PathLike[bytes]] +elif sys.version_info >= (3, 4): + from pathlib import PurePath + + _Path = Union[str, bytes, PurePath] +else: + _Path = Union[str, bytes] + +_E = TypeVar('_E', bound=_Element) +_K = TypeVar('_K', bound=Key) + +def enable_debug_trace(enabled: bool = ...) -> None: ... +def init() -> None: ... +def shutdown() -> None: ... + +class EncryptionContext: + key: Key + def __init__(self, manager: Optional[KeysManager] = None) -> None: ... + def decrypt(self, node: _Element = ...) -> _Element: ... + def encrypt_binary(self, template: _E = ..., data: bytes = ...) -> _E: ... + def encrypt_uri(self, template: _E = ..., uri: str = ...) -> _E: ... + def encrypt_xml(self, template: _E = ..., node: _Element = ...) -> _E: ... + def reset(self) -> None: ... + +class Error(Exception): ... +class InternalError(Error): ... + +class Key: + name: str + @classmethod + def from_binary_data(cls: Type[_K], klass: KeyData = ..., data: AnyStr = ...) -> _K: ... + @classmethod + def from_binary_file(cls: Type[_K], klass: KeyData = ..., filename: _Path = ...) -> _K: ... + @classmethod + def from_file(cls: Type[_K], file: _Path = ..., format: int = ..., password: Optional[str] = ...) -> _K: ... + @classmethod + def from_memory(cls: Type[_K], data: AnyStr = ..., format: int = ..., password: Optional[str] = ...) -> _K: ... + @classmethod + def generate(cls: Type[_K], klass: KeyData = ..., size: int = ..., type: int = ...) -> _K: ... + def load_cert_from_file(self, file: _Path = ..., format: int = ...) -> None: ... + def load_cert_from_memory(self, data: AnyStr, format: int = ...) -> None: ... + def __copy__(self: _K) -> _K: ... + def __deepcopy__(self: _K) -> _K: ... + +class KeysManager: + def add_key(self, key: Key = ...) -> None: ... + def load_cert(self, filename: _Path = ..., format: int = ..., type: int = ...) -> None: ... + def load_cert_from_memory(self, data: AnyStr = ..., format: int = ..., type: int = ...) -> None: ... + +class SignatureContext: + key: Key + def enable_reference_transform(self, transform: Transform = ...) -> None: ... + def enable_signature_transform(self, transform: Transform = ...) -> None: ... + def register_id(self, node: _Element = ..., id_attr: str = "ID", id_ns: Optional[str] = None) -> None: ... + def set_enabled_key_data(self, keydata_list: Iterable[KeyData] = ...) -> None: ... + def sign(self, node: _Element = ...) -> None: ... + def sign_binary(self, bytes: bytes = ..., transform: Transform = ...) -> bytes: ... + def verify(self, node: _Element = ...) -> None: ... + def verify_binary(self, bytes: bytes = ..., transform: Transform = ..., signature: bytes = ...) -> None: ... + +class VerificationError(Error): ... From c024b4711aa87982281a5322991933d1c94cd87b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 6 May 2020 20:32:00 +0200 Subject: [PATCH 143/378] add stubs for xmlsec.tree module Signed-off-by: oleg.hoefling --- src/xmlsec/tree.pyi | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 src/xmlsec/tree.pyi diff --git a/src/xmlsec/tree.pyi b/src/xmlsec/tree.pyi new file mode 100644 index 00000000..a416b001 --- /dev/null +++ b/src/xmlsec/tree.pyi @@ -0,0 +1,17 @@ +from typing import Optional, overload, Sequence + +from lxml.etree import _Element + +def add_ids(node: _Element = ..., ids: Sequence[str] = ...) -> None: ... +@overload +def find_child(parent: _Element = ..., name: str = ...) -> Optional[_Element]: ... +@overload +def find_child(parent: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... +@overload +def find_node(node: _Element = ..., name: str = ...) -> Optional[_Element]: ... +@overload +def find_node(node: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... +@overload +def find_parent(node: _Element = ..., name: str = ...) -> Optional[_Element]: ... +@overload +def find_parent(node: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... From 5318bf49cb0de737a5f2e6b5e927600e59300ddd Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 6 May 2020 20:32:26 +0200 Subject: [PATCH 144/378] add stubs for xmlsec.constants module Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 156 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 src/xmlsec/constants.pyi diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi new file mode 100644 index 00000000..fc0189f5 --- /dev/null +++ b/src/xmlsec/constants.pyi @@ -0,0 +1,156 @@ +import sys +from typing import NamedTuple + +if sys.version_info >= (3, 8): + from typing import Final, Literal +else: + from typing_extensions import Final, Literal + +class __KeyData(NamedTuple): # __KeyData type + href: str + name: str + +class __Transform(NamedTuple): # __Transform type + href: str + name: str + usage: int + +DSigNs: Literal['http://www.w3.org/2000/09/xmldsig#'] = 'http://www.w3.org/2000/09/xmldsig#' +EncNs: Literal['http://www.w3.org/2001/04/xmlenc#'] = 'http://www.w3.org/2001/04/xmlenc#' +KeyDataAes: Final[__KeyData] = __KeyData('aes', 'http://www.aleksey.com/xmlsec/2002#AESKeyValue') +KeyDataDes: Final[__KeyData] = __KeyData('des', 'http://www.aleksey.com/xmlsec/2002#DESKeyValue') +KeyDataDsa: Final[__KeyData] = __KeyData('dsa', 'http://www.w3.org/2000/09/xmldsig#DSAKeyValue') +KeyDataEcdsa: Final[__KeyData] = __KeyData('ecdsa', 'http://scap.nist.gov/specifications/tmsad/#resource-1.0') +KeyDataEncryptedKey: Final[__KeyData] = __KeyData('enc-key', 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') +KeyDataFormatBinary: Literal[1] = 1 +KeyDataFormatCertDer: Literal[8] = 8 +KeyDataFormatCertPem: Literal[7] = 7 +KeyDataFormatDer: Literal[3] = 3 +KeyDataFormatPem: Literal[2] = 2 +KeyDataFormatPkcs12: Literal[6] = 6 +KeyDataFormatPkcs8Der: Literal[5] = 5 +KeyDataFormatPkcs8Pem: Literal[4] = 4 +KeyDataFormatUnknown: Literal[0] = 0 +KeyDataHmac: Final[__KeyData] = __KeyData('hmac', 'http://www.aleksey.com/xmlsec/2002#HMACKeyValue') +KeyDataName: Final[__KeyData] = __KeyData('key-name', '(null)') +KeyDataRawX509Cert: Final[__KeyData] = __KeyData('raw-x509-cert', 'http://www.w3.org/2000/09/xmldsig#rawX509Certificate') +KeyDataRetrievalMethod: Final[__KeyData] = __KeyData('retrieval-method', '(null)') +KeyDataRsa: Final[__KeyData] = __KeyData('rsa', 'http://www.w3.org/2000/09/xmldsig#RSAKeyValue') +KeyDataTypeAny: Literal[65535] = 65535 +KeyDataTypeNone: Literal[0] = 0 +KeyDataTypePermanent: Literal[16] = 16 +KeyDataTypePrivate: Literal[2] = 2 +KeyDataTypePublic: Literal[1] = 1 +KeyDataTypeSession: Literal[8] = 8 +KeyDataTypeSymmetric: Literal[4] = 4 +KeyDataTypeTrusted: Literal[256] = 256 +KeyDataTypeUnknown: Literal[0] = 0 +KeyDataValue: Final[__KeyData] = __KeyData('key-value', '(null)') +KeyDataX509: Final[__KeyData] = __KeyData('x509', 'http://www.w3.org/2000/09/xmldsig#X509Data') +NodeCanonicalizationMethod: Literal['CanonicalizationMethod'] = 'CanonicalizationMethod' +NodeCipherData: Literal['CipherData'] = 'CipherData' +NodeCipherReference: Literal['CipherReference'] = 'CipherReference' +NodeCipherValue: Literal['CipherValue'] = 'CipherValue' +NodeDataReference: Literal['DataReference'] = 'DataReference' +NodeDigestMethod: Literal['DigestMethod'] = 'DigestMethod' +NodeDigestValue: Literal['DigestValue'] = 'DigestValue' +NodeEncryptedData: Literal['EncryptedData'] = 'EncryptedData' +NodeEncryptedKey: Literal['EncryptedKey'] = 'EncryptedKey' +NodeEncryptionMethod: Literal['EncryptionMethod'] = 'EncryptionMethod' +NodeEncryptionProperties: Literal['EncryptionProperties'] = 'EncryptionProperties' +NodeEncryptionProperty: Literal['EncryptionProperty'] = 'EncryptionProperty' +NodeKeyInfo: Literal['KeyInfo'] = 'KeyInfo' +NodeKeyName: Literal['KeyName'] = 'KeyName' +NodeKeyReference: Literal['KeyReference'] = 'KeyReference' +NodeKeyValue: Literal['KeyValue'] = 'KeyValue' +NodeManifest: Literal['Manifest'] = 'Manifest' +NodeObject: Literal['Object'] = 'Object' +NodeReference: Literal['Reference'] = 'Reference' +NodeReferenceList: Literal['ReferenceList'] = 'ReferenceList' +NodeSignature: Literal['Signature'] = 'Signature' +NodeSignatureMethod: Literal['SignatureMethod'] = 'SignatureMethod' +NodeSignatureProperties: Literal['SignatureProperties'] = 'SignatureProperties' +NodeSignatureValue: Literal['SignatureValue'] = 'SignatureValue' +NodeSignedInfo: Literal['SignedInfo'] = 'SignedInfo' +NodeX509Data: Literal['X509Data'] = 'X509Data' +Ns: Literal['http://www.aleksey.com/xmlsec/2002'] = 'http://www.aleksey.com/xmlsec/2002' +NsExcC14N: Literal['http://www.w3.org/2001/10/xml-exc-c14n#'] = 'http://www.w3.org/2001/10/xml-exc-c14n#' +NsExcC14NWithComments: Literal[ + 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' +] = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' +Soap11Ns: Literal['http://schemas.xmlsoap.org/soap/envelope/'] = 'http://schemas.xmlsoap.org/soap/envelope/' +Soap12Ns: Literal['http://www.w3.org/2002/06/soap-envelope'] = 'http://www.w3.org/2002/06/soap-envelope' +TransformAes128Cbc: Final[__Transform] = __Transform('aes128-cbc', 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 16) +TransformAes192Cbc: Final[__Transform] = __Transform('aes192-cbc', 'http://www.w3.org/2001/04/xmlenc#aes192-cbc', 16) +TransformAes256Cbc: Final[__Transform] = __Transform('aes256-cbc', 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', 16) +TransformDes3Cbc: Final[__Transform] = __Transform('tripledes-cbc', 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc', 16) +TransformDsaSha1: Final[__Transform] = __Transform('dsa-sha1', 'http://www.w3.org/2000/09/xmldsig#dsa-sha1', 8) +TransformEcdsaSha1: Final[__Transform] = __Transform('ecdsa-sha1', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1', 8) +TransformEcdsaSha224: Final[__Transform] = __Transform('ecdsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224', 8) +TransformEcdsaSha256: Final[__Transform] = __Transform('ecdsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256', 8) +TransformEcdsaSha384: Final[__Transform] = __Transform('ecdsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384', 8) +TransformEcdsaSha512: Final[__Transform] = __Transform('ecdsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512', 8) +TransformEnveloped: Final[__Transform] = __Transform( + 'enveloped-signature', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 1 +) +TransformExclC14N: Final[__Transform] = __Transform('exc-c14n', 'http://www.w3.org/2001/10/xml-exc-c14n#', 3) +TransformExclC14NWithComments: Final[__Transform] = __Transform( + 'exc-c14n-with-comments', 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments', 3 +) +TransformHmacMd5: Final[__Transform] = __Transform('hmac-md5', 'http://www.w3.org/2001/04/xmldsig-more#hmac-md5', 8) +TransformHmacRipemd160: Final[__Transform] = __Transform( + 'hmac-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160', 8 +) +TransformHmacSha1: Final[__Transform] = __Transform('hmac-sha1', 'http://www.w3.org/2000/09/xmldsig#hmac-sha1', 8) +TransformHmacSha224: Final[__Transform] = __Transform('hmac-sha224', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha224', 8) +TransformHmacSha256: Final[__Transform] = __Transform('hmac-sha256', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256', 8) +TransformHmacSha384: Final[__Transform] = __Transform('hmac-sha384', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha384', 8) +TransformHmacSha512: Final[__Transform] = __Transform('hmac-sha512', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha512', 8) +TransformInclC14N: Final[__Transform] = __Transform('c14n', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315', 3) +TransformInclC14N11: Final[__Transform] = __Transform('c14n11', 'http://www.w3.org/2006/12/xml-c14n11', 3) +TransformInclC14N11WithComments: Final[__Transform] = __Transform( + 'c14n11-with-comments', 'http://www.w3.org/2006/12/xml-c14n11#WithComments', 3 +) +TransformInclC14NWithComments: Final[__Transform] = __Transform( + 'c14n-with-comments', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments', 3 +) +TransformKWAes128: Final[__Transform] = __Transform('kw-aes128', 'http://www.w3.org/2001/04/xmlenc#kw-aes128', 16) +TransformKWAes192: Final[__Transform] = __Transform('kw-aes192', 'http://www.w3.org/2001/04/xmlenc#kw-aes192', 16) +TransformKWAes256: Final[__Transform] = __Transform('kw-aes256', 'http://www.w3.org/2001/04/xmlenc#kw-aes256', 16) +TransformKWDes3: Final[__Transform] = __Transform('kw-tripledes', 'http://www.w3.org/2001/04/xmlenc#kw-tripledes', 16) +TransformMd5: Final[__Transform] = __Transform('md5', 'http://www.w3.org/2001/04/xmldsig-more#md5', 4) +TransformRemoveXmlTagsC14N: Final[__Transform] = __Transform('remove-xml-tags-transform', '(null)', 3) +TransformRipemd160: Final[__Transform] = __Transform('ripemd160', 'http://www.w3.org/2001/04/xmlenc#ripemd160', 4) +TransformRsaMd5: Final[__Transform] = __Transform('rsa-md5', 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5', 8) +TransformRsaOaep: Final[__Transform] = __Transform('rsa-oaep-mgf1p', 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', 16) +TransformRsaPkcs1: Final[__Transform] = __Transform('rsa-1_5', 'http://www.w3.org/2001/04/xmlenc#rsa-1_5', 16) +TransformRsaRipemd160: Final[__Transform] = __Transform( + 'rsa-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160', 8 +) +TransformRsaSha1: Final[__Transform] = __Transform('rsa-sha1', 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 8) +TransformRsaSha224: Final[__Transform] = __Transform('rsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224', 8) +TransformRsaSha256: Final[__Transform] = __Transform('rsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 8) +TransformRsaSha384: Final[__Transform] = __Transform('rsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384', 8) +TransformRsaSha512: Final[__Transform] = __Transform('rsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 8) +TransformSha1: Final[__Transform] = __Transform('sha1', 'http://www.w3.org/2000/09/xmldsig#sha1', 4) +TransformSha224: Final[__Transform] = __Transform('sha224', 'http://www.w3.org/2001/04/xmldsig-more#sha224', 4) +TransformSha256: Final[__Transform] = __Transform('sha256', 'http://www.w3.org/2001/04/xmlenc#sha256', 4) +TransformSha384: Final[__Transform] = __Transform('sha384', 'http://www.w3.org/2001/04/xmldsig-more#sha384', 4) +TransformSha512: Final[__Transform] = __Transform('sha512', 'http://www.w3.org/2001/04/xmlenc#sha512', 4) +TransformUsageAny: Literal[65535] = 65535 +TransformUsageC14NMethod: Literal[2] = 2 +TransformUsageDSigTransform: Literal[1] = 1 +TransformUsageDigestMethod: Literal[4] = 4 +TransformUsageEncryptionMethod: Literal[16] = 16 +TransformUsageSignatureMethod: Literal[8] = 8 +TransformUsageUnknown: Literal[0] = 0 +TransformVisa3DHack: Final[__Transform] = __Transform('Visa3DHackTransform', '(null)', 1) +TransformXPath: Final[__Transform] = __Transform('xpath', 'http://www.w3.org/TR/1999/REC-xpath-19991116', 1) +TransformXPath2: Final[__Transform] = __Transform('xpath2', 'http://www.w3.org/2002/06/xmldsig-filter2', 1) +TransformXPointer: Final[__Transform] = __Transform('xpointer', 'http://www.w3.org/2001/04/xmldsig-more/xptr', 1) +TransformXslt: Final[__Transform] = __Transform('xslt', 'http://www.w3.org/TR/1999/REC-xslt-19991116', 1) +TypeEncContent: Literal['http://www.w3.org/2001/04/xmlenc#Content'] = 'http://www.w3.org/2001/04/xmlenc#Content' +TypeEncElement: Literal['http://www.w3.org/2001/04/xmlenc#Element'] = 'http://www.w3.org/2001/04/xmlenc#Element' +XPath2Ns: Literal['http://www.w3.org/2002/06/xmldsig-filter2'] = 'http://www.w3.org/2002/06/xmldsig-filter2' +XPathNs: Literal['http://www.w3.org/TR/1999/REC-xpath-19991116'] = 'http://www.w3.org/TR/1999/REC-xpath-19991116' +XPointerNs: Literal['http://www.w3.org/2001/04/xmldsig-more/xptr'] = 'http://www.w3.org/2001/04/xmldsig-more/xptr' From 85cda16b5b31e2782e599a2fa9bed02c2112bb39 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 6 May 2020 21:16:14 +0200 Subject: [PATCH 145/378] add stubs for xmlsec.template module Signed-off-by: oleg.hoefling --- src/xmlsec/template.pyi | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) create mode 100644 src/xmlsec/template.pyi diff --git a/src/xmlsec/template.pyi b/src/xmlsec/template.pyi new file mode 100644 index 00000000..970ed387 --- /dev/null +++ b/src/xmlsec/template.pyi @@ -0,0 +1,39 @@ +from typing import Any, Optional, Sequence, Union + +from lxml.etree import _Element + +from xmlsec.constants import __Transform as Transform + +def add_encrypted_key(node: _Element = ..., method: Transform = ...) -> _Element: ... +def add_key_name(node: _Element = ..., name: Optional[str] = ...) -> _Element: ... +def add_key_value(node: _Element = ...) -> _Element: ... +def add_reference( + node: _Element = ..., + digest_method: Transform = ..., + id: Optional[str] = ..., + uri: Optional[str] = ..., + type: Optional[str] = ..., +) -> _Element: ... +def add_transform(node: _Element = ..., transform: Transform = ...) -> Any: ... +def add_x509_data(node: _Element = ...) -> _Element: ... +def create(node: _Element = ..., c14n_method: Transform = ..., sign_method: Transform = ...) -> _Element: ... +def encrypted_data_create( + node: _Element = ..., + method: Transform = ..., + id: Optional[str] = ..., + type: Optional[str] = ..., + mime_type: Optional[str] = ..., + encoding: Optional[str] = ..., + ns: Optional[str] = ..., +) -> _Element: ... +def encrypted_data_ensure_cipher_value(node: _Element = ...) -> _Element: ... +def encrypted_data_ensure_key_info(node: _Element, id: Optional[str] = ..., ns: Optional[str] = ...) -> _Element: ... +def ensure_key_info(node: _Element = ..., id: Optional[str] = ...) -> _Element: ... +def transform_add_c14n_inclusive_namespaces(node: _Element = ..., prefixes: Union[str, Sequence[str]] = ...) -> None: ... +def x509_data_add_certificate(node: _Element = ...) -> _Element: ... +def x509_data_add_crl(node: _Element = ...) -> _Element: ... +def x509_data_add_issuer_serial(node: _Element = ...) -> _Element: ... +def x509_data_add_ski(node: _Element = ...) -> _Element: ... +def x509_data_add_subject_name(node: _Element = ...) -> _Element: ... +def x509_issuer_serial_add_issuer_name(node: _Element = ...) -> _Element: ... +def x509_issuer_serial_add_serial_number(node: _Element = ...) -> _Element: ... From d787ca8eefe10efc879eb617d8f4996cf4d52993 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:44:35 +0200 Subject: [PATCH 146/378] add rudimentary lxml stubs Signed-off-by: oleg.hoefling --- typeshed/lxml/__init__.pyi | 0 typeshed/lxml/etree.pyi | 6 ++++++ 2 files changed, 6 insertions(+) create mode 100644 typeshed/lxml/__init__.pyi create mode 100644 typeshed/lxml/etree.pyi diff --git a/typeshed/lxml/__init__.pyi b/typeshed/lxml/__init__.pyi new file mode 100644 index 00000000..e69de29b diff --git a/typeshed/lxml/etree.pyi b/typeshed/lxml/etree.pyi new file mode 100644 index 00000000..9420180f --- /dev/null +++ b/typeshed/lxml/etree.pyi @@ -0,0 +1,6 @@ +from typing import Any + +def __getattr__(name: str) -> Any: ... # incomplete + +class _Element: + def __getattr__(self, name: str) -> Any: ... # incomplete From b731866c3a29587a4efa4f1dd22c91b19000b4c1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:45:40 +0200 Subject: [PATCH 147/378] add mypy config Signed-off-by: oleg.hoefling --- mypy.ini | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 mypy.ini diff --git a/mypy.ini b/mypy.ini new file mode 100644 index 00000000..ce190e35 --- /dev/null +++ b/mypy.ini @@ -0,0 +1,17 @@ +[mypy] +files = src +mypy_path = typeshed/ +ignore_missing_imports = False +warn_unused_configs = True +disallow_subclassing_any = True +disallow_any_generics = True +disallow_untyped_calls = True +disallow_untyped_defs = True +disallow_incomplete_defs = True +check_untyped_defs = True +disallow_untyped_decorators = True +no_implicit_optional = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_return_any = True +no_implicit_reexport = True From c0b37638df89f138741e2100720297a4b7073dc2 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 10:57:19 +0200 Subject: [PATCH 148/378] package type stubs, add PEP 561 marker Signed-off-by: oleg.hoefling --- setup.py | 3 +++ src/xmlsec/py.typed | 1 + 2 files changed, 4 insertions(+) create mode 100644 src/xmlsec/py.typed diff --git a/setup.py b/setup.py index 149743e6..3965b6e2 100644 --- a/setup.py +++ b/setup.py @@ -446,4 +446,7 @@ def prepare_static_build_linux(self): 'Topic :: Text Processing :: Markup :: XML', ], zip_safe=False, + packages=['xmlsec'], + package_dir={'': 'src'}, + package_data={'xmlsec': ['py.typed', '*.pyi']}, ) diff --git a/src/xmlsec/py.typed b/src/xmlsec/py.typed new file mode 100644 index 00000000..775794d8 --- /dev/null +++ b/src/xmlsec/py.typed @@ -0,0 +1 @@ +# Marker file for PEP 561. The xmlsec package uses stub files. From 04b95a7c02267292f2399b12692ceea3e0aad79a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 17:44:02 +0200 Subject: [PATCH 149/378] use only final type by all constants Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 262 +++++++++++++++++++-------------------- 1 file changed, 127 insertions(+), 135 deletions(-) diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index fc0189f5..4352b3b2 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -2,9 +2,9 @@ import sys from typing import NamedTuple if sys.version_info >= (3, 8): - from typing import Final, Literal + from typing import Final else: - from typing_extensions import Final, Literal + from typing_extensions import Final class __KeyData(NamedTuple): # __KeyData type href: str @@ -15,142 +15,134 @@ class __Transform(NamedTuple): # __Transform type name: str usage: int -DSigNs: Literal['http://www.w3.org/2000/09/xmldsig#'] = 'http://www.w3.org/2000/09/xmldsig#' -EncNs: Literal['http://www.w3.org/2001/04/xmlenc#'] = 'http://www.w3.org/2001/04/xmlenc#' -KeyDataAes: Final[__KeyData] = __KeyData('aes', 'http://www.aleksey.com/xmlsec/2002#AESKeyValue') -KeyDataDes: Final[__KeyData] = __KeyData('des', 'http://www.aleksey.com/xmlsec/2002#DESKeyValue') -KeyDataDsa: Final[__KeyData] = __KeyData('dsa', 'http://www.w3.org/2000/09/xmldsig#DSAKeyValue') -KeyDataEcdsa: Final[__KeyData] = __KeyData('ecdsa', 'http://scap.nist.gov/specifications/tmsad/#resource-1.0') -KeyDataEncryptedKey: Final[__KeyData] = __KeyData('enc-key', 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') -KeyDataFormatBinary: Literal[1] = 1 -KeyDataFormatCertDer: Literal[8] = 8 -KeyDataFormatCertPem: Literal[7] = 7 -KeyDataFormatDer: Literal[3] = 3 -KeyDataFormatPem: Literal[2] = 2 -KeyDataFormatPkcs12: Literal[6] = 6 -KeyDataFormatPkcs8Der: Literal[5] = 5 -KeyDataFormatPkcs8Pem: Literal[4] = 4 -KeyDataFormatUnknown: Literal[0] = 0 -KeyDataHmac: Final[__KeyData] = __KeyData('hmac', 'http://www.aleksey.com/xmlsec/2002#HMACKeyValue') -KeyDataName: Final[__KeyData] = __KeyData('key-name', '(null)') -KeyDataRawX509Cert: Final[__KeyData] = __KeyData('raw-x509-cert', 'http://www.w3.org/2000/09/xmldsig#rawX509Certificate') -KeyDataRetrievalMethod: Final[__KeyData] = __KeyData('retrieval-method', '(null)') -KeyDataRsa: Final[__KeyData] = __KeyData('rsa', 'http://www.w3.org/2000/09/xmldsig#RSAKeyValue') -KeyDataTypeAny: Literal[65535] = 65535 -KeyDataTypeNone: Literal[0] = 0 -KeyDataTypePermanent: Literal[16] = 16 -KeyDataTypePrivate: Literal[2] = 2 -KeyDataTypePublic: Literal[1] = 1 -KeyDataTypeSession: Literal[8] = 8 -KeyDataTypeSymmetric: Literal[4] = 4 -KeyDataTypeTrusted: Literal[256] = 256 -KeyDataTypeUnknown: Literal[0] = 0 -KeyDataValue: Final[__KeyData] = __KeyData('key-value', '(null)') -KeyDataX509: Final[__KeyData] = __KeyData('x509', 'http://www.w3.org/2000/09/xmldsig#X509Data') -NodeCanonicalizationMethod: Literal['CanonicalizationMethod'] = 'CanonicalizationMethod' -NodeCipherData: Literal['CipherData'] = 'CipherData' -NodeCipherReference: Literal['CipherReference'] = 'CipherReference' -NodeCipherValue: Literal['CipherValue'] = 'CipherValue' -NodeDataReference: Literal['DataReference'] = 'DataReference' -NodeDigestMethod: Literal['DigestMethod'] = 'DigestMethod' -NodeDigestValue: Literal['DigestValue'] = 'DigestValue' -NodeEncryptedData: Literal['EncryptedData'] = 'EncryptedData' -NodeEncryptedKey: Literal['EncryptedKey'] = 'EncryptedKey' -NodeEncryptionMethod: Literal['EncryptionMethod'] = 'EncryptionMethod' -NodeEncryptionProperties: Literal['EncryptionProperties'] = 'EncryptionProperties' -NodeEncryptionProperty: Literal['EncryptionProperty'] = 'EncryptionProperty' -NodeKeyInfo: Literal['KeyInfo'] = 'KeyInfo' -NodeKeyName: Literal['KeyName'] = 'KeyName' -NodeKeyReference: Literal['KeyReference'] = 'KeyReference' -NodeKeyValue: Literal['KeyValue'] = 'KeyValue' -NodeManifest: Literal['Manifest'] = 'Manifest' -NodeObject: Literal['Object'] = 'Object' -NodeReference: Literal['Reference'] = 'Reference' -NodeReferenceList: Literal['ReferenceList'] = 'ReferenceList' -NodeSignature: Literal['Signature'] = 'Signature' -NodeSignatureMethod: Literal['SignatureMethod'] = 'SignatureMethod' -NodeSignatureProperties: Literal['SignatureProperties'] = 'SignatureProperties' -NodeSignatureValue: Literal['SignatureValue'] = 'SignatureValue' -NodeSignedInfo: Literal['SignedInfo'] = 'SignedInfo' -NodeX509Data: Literal['X509Data'] = 'X509Data' -Ns: Literal['http://www.aleksey.com/xmlsec/2002'] = 'http://www.aleksey.com/xmlsec/2002' -NsExcC14N: Literal['http://www.w3.org/2001/10/xml-exc-c14n#'] = 'http://www.w3.org/2001/10/xml-exc-c14n#' -NsExcC14NWithComments: Literal[ - 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' -] = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' -Soap11Ns: Literal['http://schemas.xmlsoap.org/soap/envelope/'] = 'http://schemas.xmlsoap.org/soap/envelope/' -Soap12Ns: Literal['http://www.w3.org/2002/06/soap-envelope'] = 'http://www.w3.org/2002/06/soap-envelope' -TransformAes128Cbc: Final[__Transform] = __Transform('aes128-cbc', 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 16) -TransformAes192Cbc: Final[__Transform] = __Transform('aes192-cbc', 'http://www.w3.org/2001/04/xmlenc#aes192-cbc', 16) -TransformAes256Cbc: Final[__Transform] = __Transform('aes256-cbc', 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', 16) -TransformDes3Cbc: Final[__Transform] = __Transform('tripledes-cbc', 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc', 16) -TransformDsaSha1: Final[__Transform] = __Transform('dsa-sha1', 'http://www.w3.org/2000/09/xmldsig#dsa-sha1', 8) -TransformEcdsaSha1: Final[__Transform] = __Transform('ecdsa-sha1', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1', 8) -TransformEcdsaSha224: Final[__Transform] = __Transform('ecdsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224', 8) -TransformEcdsaSha256: Final[__Transform] = __Transform('ecdsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256', 8) -TransformEcdsaSha384: Final[__Transform] = __Transform('ecdsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384', 8) -TransformEcdsaSha512: Final[__Transform] = __Transform('ecdsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512', 8) -TransformEnveloped: Final[__Transform] = __Transform( - 'enveloped-signature', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 1 -) -TransformExclC14N: Final[__Transform] = __Transform('exc-c14n', 'http://www.w3.org/2001/10/xml-exc-c14n#', 3) -TransformExclC14NWithComments: Final[__Transform] = __Transform( +DSigNs: Final = 'http://www.w3.org/2000/09/xmldsig#' +EncNs: Final = 'http://www.w3.org/2001/04/xmlenc#' +KeyDataAes: Final = __KeyData('aes', 'http://www.aleksey.com/xmlsec/2002#AESKeyValue') +KeyDataDes: Final = __KeyData('des', 'http://www.aleksey.com/xmlsec/2002#DESKeyValue') +KeyDataDsa: Final = __KeyData('dsa', 'http://www.w3.org/2000/09/xmldsig#DSAKeyValue') +KeyDataEcdsa: Final = __KeyData('ecdsa', 'http://scap.nist.gov/specifications/tmsad/#resource-1.0') +KeyDataEncryptedKey: Final = __KeyData('enc-key', 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') +KeyDataFormatBinary: Final = 1 +KeyDataFormatCertDer: Final = 8 +KeyDataFormatCertPem: Final = 7 +KeyDataFormatDer: Final = 3 +KeyDataFormatPem: Final = 2 +KeyDataFormatPkcs12: Final = 6 +KeyDataFormatPkcs8Der: Final = 5 +KeyDataFormatPkcs8Pem: Final = 4 +KeyDataFormatUnknown: Final = 0 +KeyDataHmac: Final = __KeyData('hmac', 'http://www.aleksey.com/xmlsec/2002#HMACKeyValue') +KeyDataName: Final = __KeyData('key-name', '(null)') +KeyDataRawX509Cert: Final = __KeyData('raw-x509-cert', 'http://www.w3.org/2000/09/xmldsig#rawX509Certificate') +KeyDataRetrievalMethod: Final = __KeyData('retrieval-method', '(null)') +KeyDataRsa: Final = __KeyData('rsa', 'http://www.w3.org/2000/09/xmldsig#RSAKeyValue') +KeyDataTypeAny: Final = 65535 +KeyDataTypeNone: Final = 0 +KeyDataTypePermanent: Final = 16 +KeyDataTypePrivate: Final = 2 +KeyDataTypePublic: Final = 1 +KeyDataTypeSession: Final = 8 +KeyDataTypeSymmetric: Final = 4 +KeyDataTypeTrusted: Final = 256 +KeyDataTypeUnknown: Final = 0 +KeyDataValue: Final = __KeyData('key-value', '(null)') +KeyDataX509: Final = __KeyData('x509', 'http://www.w3.org/2000/09/xmldsig#X509Data') +NodeCanonicalizationMethod: Final = 'CanonicalizationMethod' +NodeCipherData: Final = 'CipherData' +NodeCipherReference: Final = 'CipherReference' +NodeCipherValue: Final = 'CipherValue' +NodeDataReference: Final = 'DataReference' +NodeDigestMethod: Final = 'DigestMethod' +NodeDigestValue: Final = 'DigestValue' +NodeEncryptedData: Final = 'EncryptedData' +NodeEncryptedKey: Final = 'EncryptedKey' +NodeEncryptionMethod: Final = 'EncryptionMethod' +NodeEncryptionProperties: Final = 'EncryptionProperties' +NodeEncryptionProperty: Final = 'EncryptionProperty' +NodeKeyInfo: Final = 'KeyInfo' +NodeKeyName: Final = 'KeyName' +NodeKeyReference: Final = 'KeyReference' +NodeKeyValue: Final = 'KeyValue' +NodeManifest: Final = 'Manifest' +NodeObject: Final = 'Object' +NodeReference: Final = 'Reference' +NodeReferenceList: Final = 'ReferenceList' +NodeSignature: Final = 'Signature' +NodeSignatureMethod: Final = 'SignatureMethod' +NodeSignatureProperties: Final = 'SignatureProperties' +NodeSignatureValue: Final = 'SignatureValue' +NodeSignedInfo: Final = 'SignedInfo' +NodeX509Data: Final = 'X509Data' +Ns: Final = 'http://www.aleksey.com/xmlsec/2002' +NsExcC14N: Final = 'http://www.w3.org/2001/10/xml-exc-c14n#' +NsExcC14NWithComments: Final = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' +Soap11Ns: Final = 'http://schemas.xmlsoap.org/soap/envelope/' +Soap12Ns: Final = 'http://www.w3.org/2002/06/soap-envelope' +TransformAes128Cbc: Final = __Transform('aes128-cbc', 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 16) +TransformAes192Cbc: Final = __Transform('aes192-cbc', 'http://www.w3.org/2001/04/xmlenc#aes192-cbc', 16) +TransformAes256Cbc: Final = __Transform('aes256-cbc', 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', 16) +TransformDes3Cbc: Final = __Transform('tripledes-cbc', 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc', 16) +TransformDsaSha1: Final = __Transform('dsa-sha1', 'http://www.w3.org/2000/09/xmldsig#dsa-sha1', 8) +TransformEcdsaSha1: Final = __Transform('ecdsa-sha1', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1', 8) +TransformEcdsaSha224: Final = __Transform('ecdsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224', 8) +TransformEcdsaSha256: Final = __Transform('ecdsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256', 8) +TransformEcdsaSha384: Final = __Transform('ecdsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384', 8) +TransformEcdsaSha512: Final = __Transform('ecdsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512', 8) +TransformEnveloped: Final = __Transform('enveloped-signature', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 1) +TransformExclC14N: Final = __Transform('exc-c14n', 'http://www.w3.org/2001/10/xml-exc-c14n#', 3) +TransformExclC14NWithComments: Final = __Transform( 'exc-c14n-with-comments', 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments', 3 ) -TransformHmacMd5: Final[__Transform] = __Transform('hmac-md5', 'http://www.w3.org/2001/04/xmldsig-more#hmac-md5', 8) -TransformHmacRipemd160: Final[__Transform] = __Transform( - 'hmac-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160', 8 -) -TransformHmacSha1: Final[__Transform] = __Transform('hmac-sha1', 'http://www.w3.org/2000/09/xmldsig#hmac-sha1', 8) -TransformHmacSha224: Final[__Transform] = __Transform('hmac-sha224', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha224', 8) -TransformHmacSha256: Final[__Transform] = __Transform('hmac-sha256', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256', 8) -TransformHmacSha384: Final[__Transform] = __Transform('hmac-sha384', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha384', 8) -TransformHmacSha512: Final[__Transform] = __Transform('hmac-sha512', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha512', 8) -TransformInclC14N: Final[__Transform] = __Transform('c14n', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315', 3) -TransformInclC14N11: Final[__Transform] = __Transform('c14n11', 'http://www.w3.org/2006/12/xml-c14n11', 3) -TransformInclC14N11WithComments: Final[__Transform] = __Transform( +TransformHmacMd5: Final = __Transform('hmac-md5', 'http://www.w3.org/2001/04/xmldsig-more#hmac-md5', 8) +TransformHmacRipemd160: Final = __Transform('hmac-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160', 8) +TransformHmacSha1: Final = __Transform('hmac-sha1', 'http://www.w3.org/2000/09/xmldsig#hmac-sha1', 8) +TransformHmacSha224: Final = __Transform('hmac-sha224', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha224', 8) +TransformHmacSha256: Final = __Transform('hmac-sha256', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256', 8) +TransformHmacSha384: Final = __Transform('hmac-sha384', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha384', 8) +TransformHmacSha512: Final = __Transform('hmac-sha512', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha512', 8) +TransformInclC14N: Final = __Transform('c14n', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315', 3) +TransformInclC14N11: Final = __Transform('c14n11', 'http://www.w3.org/2006/12/xml-c14n11', 3) +TransformInclC14N11WithComments: Final = __Transform( 'c14n11-with-comments', 'http://www.w3.org/2006/12/xml-c14n11#WithComments', 3 ) -TransformInclC14NWithComments: Final[__Transform] = __Transform( +TransformInclC14NWithComments: Final = __Transform( 'c14n-with-comments', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments', 3 ) -TransformKWAes128: Final[__Transform] = __Transform('kw-aes128', 'http://www.w3.org/2001/04/xmlenc#kw-aes128', 16) -TransformKWAes192: Final[__Transform] = __Transform('kw-aes192', 'http://www.w3.org/2001/04/xmlenc#kw-aes192', 16) -TransformKWAes256: Final[__Transform] = __Transform('kw-aes256', 'http://www.w3.org/2001/04/xmlenc#kw-aes256', 16) -TransformKWDes3: Final[__Transform] = __Transform('kw-tripledes', 'http://www.w3.org/2001/04/xmlenc#kw-tripledes', 16) -TransformMd5: Final[__Transform] = __Transform('md5', 'http://www.w3.org/2001/04/xmldsig-more#md5', 4) -TransformRemoveXmlTagsC14N: Final[__Transform] = __Transform('remove-xml-tags-transform', '(null)', 3) -TransformRipemd160: Final[__Transform] = __Transform('ripemd160', 'http://www.w3.org/2001/04/xmlenc#ripemd160', 4) -TransformRsaMd5: Final[__Transform] = __Transform('rsa-md5', 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5', 8) -TransformRsaOaep: Final[__Transform] = __Transform('rsa-oaep-mgf1p', 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', 16) -TransformRsaPkcs1: Final[__Transform] = __Transform('rsa-1_5', 'http://www.w3.org/2001/04/xmlenc#rsa-1_5', 16) -TransformRsaRipemd160: Final[__Transform] = __Transform( - 'rsa-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160', 8 -) -TransformRsaSha1: Final[__Transform] = __Transform('rsa-sha1', 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 8) -TransformRsaSha224: Final[__Transform] = __Transform('rsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224', 8) -TransformRsaSha256: Final[__Transform] = __Transform('rsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 8) -TransformRsaSha384: Final[__Transform] = __Transform('rsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384', 8) -TransformRsaSha512: Final[__Transform] = __Transform('rsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 8) -TransformSha1: Final[__Transform] = __Transform('sha1', 'http://www.w3.org/2000/09/xmldsig#sha1', 4) -TransformSha224: Final[__Transform] = __Transform('sha224', 'http://www.w3.org/2001/04/xmldsig-more#sha224', 4) -TransformSha256: Final[__Transform] = __Transform('sha256', 'http://www.w3.org/2001/04/xmlenc#sha256', 4) -TransformSha384: Final[__Transform] = __Transform('sha384', 'http://www.w3.org/2001/04/xmldsig-more#sha384', 4) -TransformSha512: Final[__Transform] = __Transform('sha512', 'http://www.w3.org/2001/04/xmlenc#sha512', 4) -TransformUsageAny: Literal[65535] = 65535 -TransformUsageC14NMethod: Literal[2] = 2 -TransformUsageDSigTransform: Literal[1] = 1 -TransformUsageDigestMethod: Literal[4] = 4 -TransformUsageEncryptionMethod: Literal[16] = 16 -TransformUsageSignatureMethod: Literal[8] = 8 -TransformUsageUnknown: Literal[0] = 0 -TransformVisa3DHack: Final[__Transform] = __Transform('Visa3DHackTransform', '(null)', 1) -TransformXPath: Final[__Transform] = __Transform('xpath', 'http://www.w3.org/TR/1999/REC-xpath-19991116', 1) -TransformXPath2: Final[__Transform] = __Transform('xpath2', 'http://www.w3.org/2002/06/xmldsig-filter2', 1) -TransformXPointer: Final[__Transform] = __Transform('xpointer', 'http://www.w3.org/2001/04/xmldsig-more/xptr', 1) -TransformXslt: Final[__Transform] = __Transform('xslt', 'http://www.w3.org/TR/1999/REC-xslt-19991116', 1) -TypeEncContent: Literal['http://www.w3.org/2001/04/xmlenc#Content'] = 'http://www.w3.org/2001/04/xmlenc#Content' -TypeEncElement: Literal['http://www.w3.org/2001/04/xmlenc#Element'] = 'http://www.w3.org/2001/04/xmlenc#Element' -XPath2Ns: Literal['http://www.w3.org/2002/06/xmldsig-filter2'] = 'http://www.w3.org/2002/06/xmldsig-filter2' -XPathNs: Literal['http://www.w3.org/TR/1999/REC-xpath-19991116'] = 'http://www.w3.org/TR/1999/REC-xpath-19991116' -XPointerNs: Literal['http://www.w3.org/2001/04/xmldsig-more/xptr'] = 'http://www.w3.org/2001/04/xmldsig-more/xptr' +TransformKWAes128: Final = __Transform('kw-aes128', 'http://www.w3.org/2001/04/xmlenc#kw-aes128', 16) +TransformKWAes192: Final = __Transform('kw-aes192', 'http://www.w3.org/2001/04/xmlenc#kw-aes192', 16) +TransformKWAes256: Final = __Transform('kw-aes256', 'http://www.w3.org/2001/04/xmlenc#kw-aes256', 16) +TransformKWDes3: Final = __Transform('kw-tripledes', 'http://www.w3.org/2001/04/xmlenc#kw-tripledes', 16) +TransformMd5: Final = __Transform('md5', 'http://www.w3.org/2001/04/xmldsig-more#md5', 4) +TransformRemoveXmlTagsC14N: Final = __Transform('remove-xml-tags-transform', '(null)', 3) +TransformRipemd160: Final = __Transform('ripemd160', 'http://www.w3.org/2001/04/xmlenc#ripemd160', 4) +TransformRsaMd5: Final = __Transform('rsa-md5', 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5', 8) +TransformRsaOaep: Final = __Transform('rsa-oaep-mgf1p', 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', 16) +TransformRsaPkcs1: Final = __Transform('rsa-1_5', 'http://www.w3.org/2001/04/xmlenc#rsa-1_5', 16) +TransformRsaRipemd160: Final = __Transform('rsa-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160', 8) +TransformRsaSha1: Final = __Transform('rsa-sha1', 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 8) +TransformRsaSha224: Final = __Transform('rsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224', 8) +TransformRsaSha256: Final = __Transform('rsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 8) +TransformRsaSha384: Final = __Transform('rsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384', 8) +TransformRsaSha512: Final = __Transform('rsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 8) +TransformSha1: Final = __Transform('sha1', 'http://www.w3.org/2000/09/xmldsig#sha1', 4) +TransformSha224: Final = __Transform('sha224', 'http://www.w3.org/2001/04/xmldsig-more#sha224', 4) +TransformSha256: Final = __Transform('sha256', 'http://www.w3.org/2001/04/xmlenc#sha256', 4) +TransformSha384: Final = __Transform('sha384', 'http://www.w3.org/2001/04/xmldsig-more#sha384', 4) +TransformSha512: Final = __Transform('sha512', 'http://www.w3.org/2001/04/xmlenc#sha512', 4) +TransformUsageAny: Final = 65535 +TransformUsageC14NMethod: Final = 2 +TransformUsageDSigTransform: Final = 1 +TransformUsageDigestMethod: Final = 4 +TransformUsageEncryptionMethod: Final = 16 +TransformUsageSignatureMethod: Final = 8 +TransformUsageUnknown: Final = 0 +TransformVisa3DHack: Final = __Transform('Visa3DHackTransform', '(null)', 1) +TransformXPath: Final = __Transform('xpath', 'http://www.w3.org/TR/1999/REC-xpath-19991116', 1) +TransformXPath2: Final = __Transform('xpath2', 'http://www.w3.org/2002/06/xmldsig-filter2', 1) +TransformXPointer: Final = __Transform('xpointer', 'http://www.w3.org/2001/04/xmldsig-more/xptr', 1) +TransformXslt: Final = __Transform('xslt', 'http://www.w3.org/TR/1999/REC-xslt-19991116', 1) +TypeEncContent: Final = 'http://www.w3.org/2001/04/xmlenc#Content' +TypeEncElement: Final = 'http://www.w3.org/2001/04/xmlenc#Element' +XPath2Ns: Final = 'http://www.w3.org/2002/06/xmldsig-filter2' +XPathNs: Final = 'http://www.w3.org/TR/1999/REC-xpath-19991116' +XPointerNs: Final = 'http://www.w3.org/2001/04/xmldsig-more/xptr' From e3cbffd14a4a40e7a08c31c9a8144e4b8e262eba Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 18:00:09 +0200 Subject: [PATCH 150/378] first batch of typing tests Signed-off-by: oleg.hoefling --- requirements-test.txt | 1 + tests/typesafe/test_constants.yml | 405 ++++++++++++++++++++++++++++++ tests/typesafe/test_xmlsec.yml | 57 +++++ 3 files changed, 463 insertions(+) create mode 100644 tests/typesafe/test_constants.yml create mode 100644 tests/typesafe/test_xmlsec.yml diff --git a/requirements-test.txt b/requirements-test.txt index dde7de3d..29834f73 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,4 @@ -r requirements.txt pytest>=4.6.9 hypothesis +pytest-mypy-plugins diff --git a/tests/typesafe/test_constants.yml b/tests/typesafe/test_constants.yml new file mode 100644 index 00000000..8058e2aa --- /dev/null +++ b/tests/typesafe/test_constants.yml @@ -0,0 +1,405 @@ +# all tests ignore import errors b/c mypy-testing-plugin +# can't resolve local stubs, see https://github.com/typeddjango/pytest-mypy-plugins/issues/17 +- case: all-constants-are-final + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + xmlsec.constants.DSigNs = 'fizz' # E: Cannot assign to final name "DSigNs" + xmlsec.constants.EncNs = 'fizz' # E: Cannot assign to final name "EncNs" + xmlsec.constants.KeyDataAes = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataAes" + xmlsec.constants.KeyDataDes = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataDes" + xmlsec.constants.KeyDataDsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataDsa" + xmlsec.constants.KeyDataEcdsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataEcdsa" + xmlsec.constants.KeyDataEncryptedKey = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataEncryptedKey" + xmlsec.constants.KeyDataFormatBinary = -127 # E: Cannot assign to final name "KeyDataFormatBinary" + xmlsec.constants.KeyDataFormatCertDer = -127 # E: Cannot assign to final name "KeyDataFormatCertDer" + xmlsec.constants.KeyDataFormatCertPem = -127 # E: Cannot assign to final name "KeyDataFormatCertPem" + xmlsec.constants.KeyDataFormatDer = -127 # E: Cannot assign to final name "KeyDataFormatDer" + xmlsec.constants.KeyDataFormatPem = -127 # E: Cannot assign to final name "KeyDataFormatPem" + xmlsec.constants.KeyDataFormatPkcs12 = -127 # E: Cannot assign to final name "KeyDataFormatPkcs12" + xmlsec.constants.KeyDataFormatPkcs8Der = -127 # E: Cannot assign to final name "KeyDataFormatPkcs8Der" + xmlsec.constants.KeyDataFormatPkcs8Pem = -127 # E: Cannot assign to final name "KeyDataFormatPkcs8Pem" + xmlsec.constants.KeyDataFormatUnknown = -127 # E: Cannot assign to final name "KeyDataFormatUnknown" + xmlsec.constants.KeyDataHmac = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataHmac" + xmlsec.constants.KeyDataName = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataName" + xmlsec.constants.KeyDataRawX509Cert = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRawX509Cert" + xmlsec.constants.KeyDataRetrievalMethod = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRetrievalMethod" + xmlsec.constants.KeyDataRsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRsa" + xmlsec.constants.KeyDataTypeAny = -127 # E: Cannot assign to final name "KeyDataTypeAny" + xmlsec.constants.KeyDataTypeNone = -127 # E: Cannot assign to final name "KeyDataTypeNone" + xmlsec.constants.KeyDataTypePermanent = -127 # E: Cannot assign to final name "KeyDataTypePermanent" + xmlsec.constants.KeyDataTypePrivate = -127 # E: Cannot assign to final name "KeyDataTypePrivate" + xmlsec.constants.KeyDataTypePublic = -127 # E: Cannot assign to final name "KeyDataTypePublic" + xmlsec.constants.KeyDataTypeSession = -127 # E: Cannot assign to final name "KeyDataTypeSession" + xmlsec.constants.KeyDataTypeSymmetric = -127 # E: Cannot assign to final name "KeyDataTypeSymmetric" + xmlsec.constants.KeyDataTypeTrusted = -127 # E: Cannot assign to final name "KeyDataTypeTrusted" + xmlsec.constants.KeyDataTypeUnknown = -127 # E: Cannot assign to final name "KeyDataTypeUnknown" + xmlsec.constants.KeyDataValue = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataValue" + xmlsec.constants.KeyDataX509 = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataX509" + xmlsec.constants.NodeCanonicalizationMethod = 'fizz' # E: Cannot assign to final name "NodeCanonicalizationMethod" + xmlsec.constants.NodeCipherData = 'fizz' # E: Cannot assign to final name "NodeCipherData" + xmlsec.constants.NodeCipherReference = 'fizz' # E: Cannot assign to final name "NodeCipherReference" + xmlsec.constants.NodeCipherValue = 'fizz' # E: Cannot assign to final name "NodeCipherValue" + xmlsec.constants.NodeDataReference = 'fizz' # E: Cannot assign to final name "NodeDataReference" + xmlsec.constants.NodeDigestMethod = 'fizz' # E: Cannot assign to final name "NodeDigestMethod" + xmlsec.constants.NodeDigestValue = 'fizz' # E: Cannot assign to final name "NodeDigestValue" + xmlsec.constants.NodeEncryptedData = 'fizz' # E: Cannot assign to final name "NodeEncryptedData" + xmlsec.constants.NodeEncryptedKey = 'fizz' # E: Cannot assign to final name "NodeEncryptedKey" + xmlsec.constants.NodeEncryptionMethod = 'fizz' # E: Cannot assign to final name "NodeEncryptionMethod" + xmlsec.constants.NodeEncryptionProperties = 'fizz' # E: Cannot assign to final name "NodeEncryptionProperties" + xmlsec.constants.NodeEncryptionProperty = 'fizz' # E: Cannot assign to final name "NodeEncryptionProperty" + xmlsec.constants.NodeKeyInfo = 'fizz' # E: Cannot assign to final name "NodeKeyInfo" + xmlsec.constants.NodeKeyName = 'fizz' # E: Cannot assign to final name "NodeKeyName" + xmlsec.constants.NodeKeyReference = 'fizz' # E: Cannot assign to final name "NodeKeyReference" + xmlsec.constants.NodeKeyValue = 'fizz' # E: Cannot assign to final name "NodeKeyValue" + xmlsec.constants.NodeManifest = 'fizz' # E: Cannot assign to final name "NodeManifest" + xmlsec.constants.NodeObject = 'fizz' # E: Cannot assign to final name "NodeObject" + xmlsec.constants.NodeReference = 'fizz' # E: Cannot assign to final name "NodeReference" + xmlsec.constants.NodeReferenceList = 'fizz' # E: Cannot assign to final name "NodeReferenceList" + xmlsec.constants.NodeSignature = 'fizz' # E: Cannot assign to final name "NodeSignature" + xmlsec.constants.NodeSignatureMethod = 'fizz' # E: Cannot assign to final name "NodeSignatureMethod" + xmlsec.constants.NodeSignatureProperties = 'fizz' # E: Cannot assign to final name "NodeSignatureProperties" + xmlsec.constants.NodeSignatureValue = 'fizz' # E: Cannot assign to final name "NodeSignatureValue" + xmlsec.constants.NodeSignedInfo = 'fizz' # E: Cannot assign to final name "NodeSignedInfo" + xmlsec.constants.NodeX509Data = 'fizz' # E: Cannot assign to final name "NodeX509Data" + xmlsec.constants.Ns = 'fizz' # E: Cannot assign to final name "Ns" + xmlsec.constants.NsExcC14N = 'fizz' # E: Cannot assign to final name "NsExcC14N" + xmlsec.constants.NsExcC14NWithComments = 'fizz' # E: Cannot assign to final name "NsExcC14NWithComments" + xmlsec.constants.Soap11Ns = 'fizz' # E: Cannot assign to final name "Soap11Ns" + xmlsec.constants.Soap12Ns = 'fizz' # E: Cannot assign to final name "Soap12Ns" + xmlsec.constants.TransformAes128Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes128Cbc" + xmlsec.constants.TransformAes192Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes192Cbc" + xmlsec.constants.TransformAes256Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes256Cbc" + xmlsec.constants.TransformDes3Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformDes3Cbc" + xmlsec.constants.TransformDsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformDsaSha1" + xmlsec.constants.TransformEcdsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha1" + xmlsec.constants.TransformEcdsaSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha224" + xmlsec.constants.TransformEcdsaSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha256" + xmlsec.constants.TransformEcdsaSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha384" + xmlsec.constants.TransformEcdsaSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha512" + xmlsec.constants.TransformEnveloped = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEnveloped" + xmlsec.constants.TransformExclC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformExclC14N" + xmlsec.constants.TransformExclC14NWithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformExclC14NWithComments" + xmlsec.constants.TransformHmacMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacMd5" + xmlsec.constants.TransformHmacRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacRipemd160" + xmlsec.constants.TransformHmacSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha1" + xmlsec.constants.TransformHmacSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha224" + xmlsec.constants.TransformHmacSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha256" + xmlsec.constants.TransformHmacSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha384" + xmlsec.constants.TransformHmacSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha512" + xmlsec.constants.TransformInclC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N" + xmlsec.constants.TransformInclC14N11 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N11" + xmlsec.constants.TransformInclC14N11WithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N11WithComments" + xmlsec.constants.TransformInclC14NWithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14NWithComments" + xmlsec.constants.TransformKWAes128 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes128" + xmlsec.constants.TransformKWAes192 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes192" + xmlsec.constants.TransformKWAes256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes256" + xmlsec.constants.TransformKWDes3 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWDes3" + xmlsec.constants.TransformMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformMd5" + xmlsec.constants.TransformRemoveXmlTagsC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRemoveXmlTagsC14N" + xmlsec.constants.TransformRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRipemd160" + xmlsec.constants.TransformRsaMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaMd5" + xmlsec.constants.TransformRsaOaep = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaOaep" + xmlsec.constants.TransformRsaPkcs1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaPkcs1" + xmlsec.constants.TransformRsaRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaRipemd160" + xmlsec.constants.TransformRsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha1" + xmlsec.constants.TransformRsaSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha224" + xmlsec.constants.TransformRsaSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha256" + xmlsec.constants.TransformRsaSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha384" + xmlsec.constants.TransformRsaSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha512" + xmlsec.constants.TransformSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha1" + xmlsec.constants.TransformSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha224" + xmlsec.constants.TransformSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha256" + xmlsec.constants.TransformSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha384" + xmlsec.constants.TransformSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha512" + xmlsec.constants.TransformUsageAny = -127 # E: Cannot assign to final name "TransformUsageAny" + xmlsec.constants.TransformUsageC14NMethod = -127 # E: Cannot assign to final name "TransformUsageC14NMethod" + xmlsec.constants.TransformUsageDSigTransform = -127 # E: Cannot assign to final name "TransformUsageDSigTransform" + xmlsec.constants.TransformUsageDigestMethod = -127 # E: Cannot assign to final name "TransformUsageDigestMethod" + xmlsec.constants.TransformUsageEncryptionMethod = -127 # E: Cannot assign to final name "TransformUsageEncryptionMethod" + xmlsec.constants.TransformUsageSignatureMethod = -127 # E: Cannot assign to final name "TransformUsageSignatureMethod" + xmlsec.constants.TransformUsageUnknown = -127 # E: Cannot assign to final name "TransformUsageUnknown" + xmlsec.constants.TransformVisa3DHack = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformVisa3DHack" + xmlsec.constants.TransformXPath = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPath" + xmlsec.constants.TransformXPath2 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPath2" + xmlsec.constants.TransformXPointer = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPointer" + xmlsec.constants.TransformXslt = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXslt" + xmlsec.constants.TypeEncContent = 'fizz' # E: Cannot assign to final name "TypeEncContent" + xmlsec.constants.TypeEncElement = 'fizz' # E: Cannot assign to final name "TypeEncElement" + xmlsec.constants.XPath2Ns = 'fizz' # E: Cannot assign to final name "XPath2Ns" + xmlsec.constants.XPathNs = 'fizz' # E: Cannot assign to final name "XPathNs" + xmlsec.constants.XPointerNs = 'fizz' # E: Cannot assign to final name "XPointerNs" + +- case: primitive-constants-have-literal-types + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.DSigNs) # N: Revealed type is 'Literal['http://www.w3.org/2000/09/xmldsig#']?' + reveal_type(xmlsec.constants.EncNs) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#']?' + reveal_type(xmlsec.constants.KeyDataFormatBinary) # N: Revealed type is 'Literal[1]?' + reveal_type(xmlsec.constants.KeyDataFormatCertDer) # N: Revealed type is 'Literal[8]?' + reveal_type(xmlsec.constants.KeyDataFormatCertPem) # N: Revealed type is 'Literal[7]?' + reveal_type(xmlsec.constants.KeyDataFormatDer) # N: Revealed type is 'Literal[3]?' + reveal_type(xmlsec.constants.KeyDataFormatPem) # N: Revealed type is 'Literal[2]?' + reveal_type(xmlsec.constants.KeyDataFormatPkcs12) # N: Revealed type is 'Literal[6]?' + reveal_type(xmlsec.constants.KeyDataFormatPkcs8Der) # N: Revealed type is 'Literal[5]?' + reveal_type(xmlsec.constants.KeyDataFormatPkcs8Pem) # N: Revealed type is 'Literal[4]?' + reveal_type(xmlsec.constants.KeyDataFormatUnknown) # N: Revealed type is 'Literal[0]?' + reveal_type(xmlsec.constants.KeyDataTypeAny) # N: Revealed type is 'Literal[65535]?' + reveal_type(xmlsec.constants.KeyDataTypeNone) # N: Revealed type is 'Literal[0]?' + reveal_type(xmlsec.constants.KeyDataTypePermanent) # N: Revealed type is 'Literal[16]?' + reveal_type(xmlsec.constants.KeyDataTypePrivate) # N: Revealed type is 'Literal[2]?' + reveal_type(xmlsec.constants.KeyDataTypePublic) # N: Revealed type is 'Literal[1]?' + reveal_type(xmlsec.constants.KeyDataTypeSession) # N: Revealed type is 'Literal[8]?' + reveal_type(xmlsec.constants.KeyDataTypeSymmetric) # N: Revealed type is 'Literal[4]?' + reveal_type(xmlsec.constants.KeyDataTypeTrusted) # N: Revealed type is 'Literal[256]?' + reveal_type(xmlsec.constants.KeyDataTypeUnknown) # N: Revealed type is 'Literal[0]?' + reveal_type(xmlsec.constants.NodeCanonicalizationMethod) # N: Revealed type is 'Literal['CanonicalizationMethod']?' + reveal_type(xmlsec.constants.NodeCipherData) # N: Revealed type is 'Literal['CipherData']?' + reveal_type(xmlsec.constants.NodeCipherReference) # N: Revealed type is 'Literal['CipherReference']?' + reveal_type(xmlsec.constants.NodeCipherValue) # N: Revealed type is 'Literal['CipherValue']?' + reveal_type(xmlsec.constants.NodeDataReference) # N: Revealed type is 'Literal['DataReference']?' + reveal_type(xmlsec.constants.NodeDigestMethod) # N: Revealed type is 'Literal['DigestMethod']?' + reveal_type(xmlsec.constants.NodeDigestValue) # N: Revealed type is 'Literal['DigestValue']?' + reveal_type(xmlsec.constants.NodeEncryptedData) # N: Revealed type is 'Literal['EncryptedData']?' + reveal_type(xmlsec.constants.NodeEncryptedKey) # N: Revealed type is 'Literal['EncryptedKey']?' + reveal_type(xmlsec.constants.NodeEncryptionMethod) # N: Revealed type is 'Literal['EncryptionMethod']?' + reveal_type(xmlsec.constants.NodeEncryptionProperties) # N: Revealed type is 'Literal['EncryptionProperties']?' + reveal_type(xmlsec.constants.NodeEncryptionProperty) # N: Revealed type is 'Literal['EncryptionProperty']?' + reveal_type(xmlsec.constants.NodeKeyInfo) # N: Revealed type is 'Literal['KeyInfo']?' + reveal_type(xmlsec.constants.NodeKeyName) # N: Revealed type is 'Literal['KeyName']?' + reveal_type(xmlsec.constants.NodeKeyReference) # N: Revealed type is 'Literal['KeyReference']?' + reveal_type(xmlsec.constants.NodeKeyValue) # N: Revealed type is 'Literal['KeyValue']?' + reveal_type(xmlsec.constants.NodeManifest) # N: Revealed type is 'Literal['Manifest']?' + reveal_type(xmlsec.constants.NodeObject) # N: Revealed type is 'Literal['Object']?' + reveal_type(xmlsec.constants.NodeReference) # N: Revealed type is 'Literal['Reference']?' + reveal_type(xmlsec.constants.NodeReferenceList) # N: Revealed type is 'Literal['ReferenceList']?' + reveal_type(xmlsec.constants.NodeSignature) # N: Revealed type is 'Literal['Signature']?' + reveal_type(xmlsec.constants.NodeSignatureMethod) # N: Revealed type is 'Literal['SignatureMethod']?' + reveal_type(xmlsec.constants.NodeSignatureProperties) # N: Revealed type is 'Literal['SignatureProperties']?' + reveal_type(xmlsec.constants.NodeSignatureValue) # N: Revealed type is 'Literal['SignatureValue']?' + reveal_type(xmlsec.constants.NodeSignedInfo) # N: Revealed type is 'Literal['SignedInfo']?' + reveal_type(xmlsec.constants.NodeX509Data) # N: Revealed type is 'Literal['X509Data']?' + reveal_type(xmlsec.constants.Ns) # N: Revealed type is 'Literal['http://www.aleksey.com/xmlsec/2002']?' + reveal_type(xmlsec.constants.NsExcC14N) # N: Revealed type is 'Literal['http://www.w3.org/2001/10/xml-exc-c14n#']?' + reveal_type(xmlsec.constants.NsExcC14NWithComments) # N: Revealed type is 'Literal['http://www.w3.org/2001/10/xml-exc-c14n#WithComments']?' + reveal_type(xmlsec.constants.Soap11Ns) # N: Revealed type is 'Literal['http://schemas.xmlsoap.org/soap/envelope/']?' + reveal_type(xmlsec.constants.Soap12Ns) # N: Revealed type is 'Literal['http://www.w3.org/2002/06/soap-envelope']?' + reveal_type(xmlsec.constants.TransformUsageAny) # N: Revealed type is 'Literal[65535]?' + reveal_type(xmlsec.constants.TransformUsageC14NMethod) # N: Revealed type is 'Literal[2]?' + reveal_type(xmlsec.constants.TransformUsageDSigTransform) # N: Revealed type is 'Literal[1]?' + reveal_type(xmlsec.constants.TransformUsageDigestMethod) # N: Revealed type is 'Literal[4]?' + reveal_type(xmlsec.constants.TransformUsageEncryptionMethod) # N: Revealed type is 'Literal[16]?' + reveal_type(xmlsec.constants.TransformUsageSignatureMethod) # N: Revealed type is 'Literal[8]?' + reveal_type(xmlsec.constants.TransformUsageUnknown) # N: Revealed type is 'Literal[0]?' + reveal_type(xmlsec.constants.TypeEncContent) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#Content']?' + reveal_type(xmlsec.constants.TypeEncElement) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#Element']?' + reveal_type(xmlsec.constants.XPath2Ns) # N: Revealed type is 'Literal['http://www.w3.org/2002/06/xmldsig-filter2']?' + reveal_type(xmlsec.constants.XPathNs) # N: Revealed type is 'Literal['http://www.w3.org/TR/1999/REC-xpath-19991116']?' + reveal_type(xmlsec.constants.XPointerNs) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmldsig-more/xptr']?' + +- case: transform-constants-href-attribute-has-type-string + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.TransformAes128Cbc.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformAes192Cbc.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformAes256Cbc.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformDes3Cbc.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformDsaSha1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha224.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha256.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha384.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha512.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEnveloped.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformExclC14N.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformExclC14NWithComments.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacMd5.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacRipemd160.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha224.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha256.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha384.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha512.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N11.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N11WithComments.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14NWithComments.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes128.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes192.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes256.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWDes3.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformMd5.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRipemd160.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaMd5.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaOaep.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaPkcs1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaRipemd160.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha224.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha256.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha384.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha512.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha1.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha224.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha256.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha384.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha512.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformVisa3DHack.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPath.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPath2.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPointer.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXslt.href) # N: Revealed type is 'builtins.str' + +- case: transform-constants-name-attribute-has-type-string + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.TransformAes128Cbc.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformAes192Cbc.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformAes256Cbc.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformDes3Cbc.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformDsaSha1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha224.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha256.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha384.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEcdsaSha512.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformEnveloped.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformExclC14N.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformExclC14NWithComments.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacMd5.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacRipemd160.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha224.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha256.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha384.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformHmacSha512.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N11.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14N11WithComments.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformInclC14NWithComments.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes128.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes192.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWAes256.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformKWDes3.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformMd5.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRipemd160.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaMd5.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaOaep.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaPkcs1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaRipemd160.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha224.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha256.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha384.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformRsaSha512.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha1.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha224.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha256.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha384.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformSha512.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformVisa3DHack.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPath.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPath2.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXPointer.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.TransformXslt.name) # N: Revealed type is 'builtins.str' + +- case: transform-constants-usage-attribute-has-type-int + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.TransformAes128Cbc.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformAes192Cbc.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformAes256Cbc.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformDes3Cbc.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformDsaSha1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEcdsaSha1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEcdsaSha224.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEcdsaSha256.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEcdsaSha384.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEcdsaSha512.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformEnveloped.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformExclC14N.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformExclC14NWithComments.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacMd5.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacRipemd160.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacSha1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacSha224.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacSha256.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacSha384.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformHmacSha512.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformInclC14N.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformInclC14N11.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformInclC14N11WithComments.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformInclC14NWithComments.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformKWAes128.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformKWAes192.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformKWAes256.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformKWDes3.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformMd5.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRipemd160.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaMd5.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaOaep.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaPkcs1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaRipemd160.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaSha1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaSha224.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaSha256.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaSha384.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformRsaSha512.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformSha1.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformSha224.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformSha256.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformSha384.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformSha512.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformVisa3DHack.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformXPath.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformXPath2.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformXPointer.usage) # N: Revealed type is 'builtins.int' + reveal_type(xmlsec.constants.TransformXslt.usage) # N: Revealed type is 'builtins.int' + +- case: keydata-constants-name-attribute-has-type-string + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.KeyDataAes.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataDes.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataDsa.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataEcdsa.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataEncryptedKey.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataHmac.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataName.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRawX509Cert.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRetrievalMethod.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRsa.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataValue.name) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataX509.name) # N: Revealed type is 'builtins.str' + +- case: keydata-constants-href-attribute-has-type-string + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + reveal_type(xmlsec.constants.KeyDataAes.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataDes.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataDsa.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataEcdsa.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataEncryptedKey.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataHmac.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataName.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRawX509Cert.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRetrievalMethod.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataRsa.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataValue.href) # N: Revealed type is 'builtins.str' + reveal_type(xmlsec.constants.KeyDataX509.href) # N: Revealed type is 'builtins.str' diff --git a/tests/typesafe/test_xmlsec.yml b/tests/typesafe/test_xmlsec.yml new file mode 100644 index 00000000..9750d76a --- /dev/null +++ b/tests/typesafe/test_xmlsec.yml @@ -0,0 +1,57 @@ +# all tests ignore import errors b/c mypy-testing-plugin +# can't resolve local stubs, see https://github.com/typeddjango/pytest-mypy-plugins/issues/17 +- case: module-functions-allowed-calls + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + xmlsec.enable_debug_trace() + xmlsec.enable_debug_trace(True) + xmlsec.enable_debug_trace(enabled=True) + xmlsec.enable_debug_trace(enabled=False) + xmlsec.init() + xmlsec.shutdown() + +- case: module-functions-disallowed-calls + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + xmlsec.enable_debug_trace('') # E: Argument 1 to "enable_debug_trace" has incompatible type "str"; expected "bool" + xmlsec.enable_debug_trace(None) # E: Argument 1 to "enable_debug_trace" has incompatible type "None"; expected "bool" + xmlsec.enable_debug_trace(1) # E: Argument 1 to "enable_debug_trace" has incompatible type "int"; expected "bool" + xmlsec.enable_debug_trace(enabled='') # E: Argument "enabled" to "enable_debug_trace" has incompatible type "str"; expected "bool" + xmlsec.enable_debug_trace(enabled=None) # E: Argument "enabled" to "enable_debug_trace" has incompatible type "None"; expected "bool" + xmlsec.enable_debug_trace(enabled=1) # E: Argument "enabled" to "enable_debug_trace" has incompatible type "int"; expected "bool" + +- case: encyption-context-init + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + ctx = xmlsec.EncryptionContext() + + mgr = xmlsec.KeysManager() + ctx = xmlsec.EncryptionContext(mgr) + ctx = xmlsec.EncryptionContext(manager=mgr) + ctx = xmlsec.EncryptionContext(None) + ctx = xmlsec.EncryptionContext(manager=None) + + ctx = xmlsec.EncryptionContext(True) # E: Argument 1 to "EncryptionContext" has incompatible type "bool"; expected "Optional[KeysManager]" + ctx = xmlsec.EncryptionContext('') # E: Argument 1 to "EncryptionContext" has incompatible type "str"; expected "Optional[KeysManager]" + ctx = xmlsec.EncryptionContext(1) # E: Argument 1 to "EncryptionContext" has incompatible type "int"; expected "Optional[KeysManager]" + ctx = xmlsec.EncryptionContext(manager=True) # E: Argument "manager" to "EncryptionContext" has incompatible type "bool"; expected "Optional[KeysManager]" + ctx = xmlsec.EncryptionContext(manager='') # E: Argument "manager" to "EncryptionContext" has incompatible type "str"; expected "Optional[KeysManager]" + ctx = xmlsec.EncryptionContext(manager=1) # E: Argument "manager" to "EncryptionContext" has incompatible type "int"; expected "Optional[KeysManager]" + +- case: encyption-context-attributes + mypy_config: + ignore_missing_imports = True + main: | + import xmlsec + ctx = xmlsec.EncryptionContext() + reveal_type(ctx.key) # N: Revealed type is 'xmlsec.Key' + ctx.key = None # E: Incompatible types in assignment (expression has type "None", variable has type "Key") + ctx.key = True # E: Incompatible types in assignment (expression has type "bool", variable has type "Key") + ctx.key = '' # E: Incompatible types in assignment (expression has type "str", variable has type "Key") + ctx.key = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Key") From 787298889fd85dffb597dee6571dead42227c7d6 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 7 May 2020 18:12:11 +0200 Subject: [PATCH 151/378] add test to validate generated stub constants.pyi Signed-off-by: oleg.hoefling --- tests/test_type_stubs.py | 71 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 71 insertions(+) create mode 100644 tests/test_type_stubs.py diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py new file mode 100644 index 00000000..8310615b --- /dev/null +++ b/tests/test_type_stubs.py @@ -0,0 +1,71 @@ +"""Test type stubs for correctness where possible.""" + +import os +import sys + +import pytest + +import xmlsec + +black = pytest.importorskip('black') + + +if sys.version_info >= (3, 4): + from pathlib import Path +else: + from _pytest.pathlib import Path + + +constants_stub_header = """ +import sys +from typing import NamedTuple + +if sys.version_info >= (3, 8): + from typing import Final, Literal +else: + from typing_extensions import Final, Literal + + +class __KeyData(NamedTuple): # __KeyData type + href: str + name: str + + +class __Transform(NamedTuple): # __Transform type + href: str + name: str + usage: int + + +""" + + +def gen_constants_stub(): + """ + Generate contents of the file:`xmlsec/constants.pyi`. + + Simply load all constants at runtime, + generate appropriate type hint for each constant type. + """ + + def process_constant(name): + """Generate line in stub file for constant name.""" + obj = getattr(xmlsec.constants, name) + return '{name}: Final = {obj!r}'.format(name=name, obj=obj) + + names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__'))) + lines = [process_constant(name) for name in names] + return constants_stub_header + os.linesep.join(lines) + + +def test_xmlsec_constants_stub(request): + """ + Generate the stub file for :mod:`xmlsec.constants` from existing code. + + Compare it against the existing stub :file:`xmlsec/constants.pyi`. + """ + rootdir = Path(str(request.config.rootdir)) + stub = rootdir / 'src' / 'xmlsec' / 'constants.pyi' + mode = black.FileMode(target_versions=[black.TargetVersion.PY38], line_length=130, is_pyi=True, string_normalization=False) + formatted = black.format_file_contents(gen_constants_stub(), fast=False, mode=mode) + assert formatted == stub.read_text() From 329cff84115473731979015390f86e6394e6fb2f Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 8 May 2020 16:55:12 +0200 Subject: [PATCH 152/378] fix file arg types, complete optional args in xmlsec.template functions Signed-off-by: oleg.hoefling --- src/xmlsec/__init__.pyi | 8 +++++--- src/xmlsec/template.pyi | 12 +++++++++--- 2 files changed, 14 insertions(+), 6 deletions(-) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 5c2edd74..eac54966 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,5 +1,5 @@ import sys -from typing import AnyStr, Iterable, Optional, Type, TypeVar, Union +from typing import AnyStr, IO, Iterable, Optional, Type, TypeVar, Union from lxml.etree import _Element @@ -43,12 +43,14 @@ class Key: @classmethod def from_binary_file(cls: Type[_K], klass: KeyData = ..., filename: _Path = ...) -> _K: ... @classmethod - def from_file(cls: Type[_K], file: _Path = ..., format: int = ..., password: Optional[str] = ...) -> _K: ... + def from_file( + cls: Type[_K], file: Union[_Path, IO[AnyStr]] = ..., format: int = ..., password: Optional[str] = ... + ) -> _K: ... @classmethod def from_memory(cls: Type[_K], data: AnyStr = ..., format: int = ..., password: Optional[str] = ...) -> _K: ... @classmethod def generate(cls: Type[_K], klass: KeyData = ..., size: int = ..., type: int = ...) -> _K: ... - def load_cert_from_file(self, file: _Path = ..., format: int = ...) -> None: ... + def load_cert_from_file(self, file: Union[_Path, IO[AnyStr]] = ..., format: int = ...) -> None: ... def load_cert_from_memory(self, data: AnyStr, format: int = ...) -> None: ... def __copy__(self: _K) -> _K: ... def __deepcopy__(self: _K) -> _K: ... diff --git a/src/xmlsec/template.pyi b/src/xmlsec/template.pyi index 970ed387..96ee3d0b 100644 --- a/src/xmlsec/template.pyi +++ b/src/xmlsec/template.pyi @@ -4,7 +4,13 @@ from lxml.etree import _Element from xmlsec.constants import __Transform as Transform -def add_encrypted_key(node: _Element = ..., method: Transform = ...) -> _Element: ... +def add_encrypted_key( + node: _Element = ..., + method: Transform = ..., + id: Optional[str] = None, + type: Optional[str] = None, + recipient: Optional[str] = None, +) -> _Element: ... def add_key_name(node: _Element = ..., name: Optional[str] = ...) -> _Element: ... def add_key_value(node: _Element = ...) -> _Element: ... def add_reference( @@ -35,5 +41,5 @@ def x509_data_add_crl(node: _Element = ...) -> _Element: ... def x509_data_add_issuer_serial(node: _Element = ...) -> _Element: ... def x509_data_add_ski(node: _Element = ...) -> _Element: ... def x509_data_add_subject_name(node: _Element = ...) -> _Element: ... -def x509_issuer_serial_add_issuer_name(node: _Element = ...) -> _Element: ... -def x509_issuer_serial_add_serial_number(node: _Element = ...) -> _Element: ... +def x509_issuer_serial_add_issuer_name(node: _Element = ..., name: Optional[str] = ...) -> _Element: ... +def x509_issuer_serial_add_serial_number(node: _Element = ..., serial: Optional[str] = ...) -> _Element: ... From 32a5a695f3a836547c1c71f273b24863af5f95c5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 14 May 2020 12:02:58 +0200 Subject: [PATCH 153/378] add typing trove classifier Signed-off-by: oleg.hoefling --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 3965b6e2..962114cd 100644 --- a/setup.py +++ b/setup.py @@ -444,6 +444,7 @@ def prepare_static_build_linux(self): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Topic :: Text Processing :: Markup :: XML', + 'Typing :: Typed', ], zip_safe=False, packages=['xmlsec'], From 95b38fefccc4dbd0d507b907bb03edf37d8e8c77 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 17 May 2020 23:37:08 +0200 Subject: [PATCH 154/378] remove type stubs tests for now Signed-off-by: oleg.hoefling --- requirements-test.txt | 1 - tests/typesafe/test_constants.yml | 405 ------------------------------ tests/typesafe/test_xmlsec.yml | 57 ----- 3 files changed, 463 deletions(-) delete mode 100644 tests/typesafe/test_constants.yml delete mode 100644 tests/typesafe/test_xmlsec.yml diff --git a/requirements-test.txt b/requirements-test.txt index 29834f73..dde7de3d 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,3 @@ -r requirements.txt pytest>=4.6.9 hypothesis -pytest-mypy-plugins diff --git a/tests/typesafe/test_constants.yml b/tests/typesafe/test_constants.yml deleted file mode 100644 index 8058e2aa..00000000 --- a/tests/typesafe/test_constants.yml +++ /dev/null @@ -1,405 +0,0 @@ -# all tests ignore import errors b/c mypy-testing-plugin -# can't resolve local stubs, see https://github.com/typeddjango/pytest-mypy-plugins/issues/17 -- case: all-constants-are-final - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - xmlsec.constants.DSigNs = 'fizz' # E: Cannot assign to final name "DSigNs" - xmlsec.constants.EncNs = 'fizz' # E: Cannot assign to final name "EncNs" - xmlsec.constants.KeyDataAes = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataAes" - xmlsec.constants.KeyDataDes = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataDes" - xmlsec.constants.KeyDataDsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataDsa" - xmlsec.constants.KeyDataEcdsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataEcdsa" - xmlsec.constants.KeyDataEncryptedKey = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataEncryptedKey" - xmlsec.constants.KeyDataFormatBinary = -127 # E: Cannot assign to final name "KeyDataFormatBinary" - xmlsec.constants.KeyDataFormatCertDer = -127 # E: Cannot assign to final name "KeyDataFormatCertDer" - xmlsec.constants.KeyDataFormatCertPem = -127 # E: Cannot assign to final name "KeyDataFormatCertPem" - xmlsec.constants.KeyDataFormatDer = -127 # E: Cannot assign to final name "KeyDataFormatDer" - xmlsec.constants.KeyDataFormatPem = -127 # E: Cannot assign to final name "KeyDataFormatPem" - xmlsec.constants.KeyDataFormatPkcs12 = -127 # E: Cannot assign to final name "KeyDataFormatPkcs12" - xmlsec.constants.KeyDataFormatPkcs8Der = -127 # E: Cannot assign to final name "KeyDataFormatPkcs8Der" - xmlsec.constants.KeyDataFormatPkcs8Pem = -127 # E: Cannot assign to final name "KeyDataFormatPkcs8Pem" - xmlsec.constants.KeyDataFormatUnknown = -127 # E: Cannot assign to final name "KeyDataFormatUnknown" - xmlsec.constants.KeyDataHmac = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataHmac" - xmlsec.constants.KeyDataName = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataName" - xmlsec.constants.KeyDataRawX509Cert = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRawX509Cert" - xmlsec.constants.KeyDataRetrievalMethod = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRetrievalMethod" - xmlsec.constants.KeyDataRsa = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataRsa" - xmlsec.constants.KeyDataTypeAny = -127 # E: Cannot assign to final name "KeyDataTypeAny" - xmlsec.constants.KeyDataTypeNone = -127 # E: Cannot assign to final name "KeyDataTypeNone" - xmlsec.constants.KeyDataTypePermanent = -127 # E: Cannot assign to final name "KeyDataTypePermanent" - xmlsec.constants.KeyDataTypePrivate = -127 # E: Cannot assign to final name "KeyDataTypePrivate" - xmlsec.constants.KeyDataTypePublic = -127 # E: Cannot assign to final name "KeyDataTypePublic" - xmlsec.constants.KeyDataTypeSession = -127 # E: Cannot assign to final name "KeyDataTypeSession" - xmlsec.constants.KeyDataTypeSymmetric = -127 # E: Cannot assign to final name "KeyDataTypeSymmetric" - xmlsec.constants.KeyDataTypeTrusted = -127 # E: Cannot assign to final name "KeyDataTypeTrusted" - xmlsec.constants.KeyDataTypeUnknown = -127 # E: Cannot assign to final name "KeyDataTypeUnknown" - xmlsec.constants.KeyDataValue = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataValue" - xmlsec.constants.KeyDataX509 = xmlsec.constants.__KeyData('', '') # E: Cannot assign to final name "KeyDataX509" - xmlsec.constants.NodeCanonicalizationMethod = 'fizz' # E: Cannot assign to final name "NodeCanonicalizationMethod" - xmlsec.constants.NodeCipherData = 'fizz' # E: Cannot assign to final name "NodeCipherData" - xmlsec.constants.NodeCipherReference = 'fizz' # E: Cannot assign to final name "NodeCipherReference" - xmlsec.constants.NodeCipherValue = 'fizz' # E: Cannot assign to final name "NodeCipherValue" - xmlsec.constants.NodeDataReference = 'fizz' # E: Cannot assign to final name "NodeDataReference" - xmlsec.constants.NodeDigestMethod = 'fizz' # E: Cannot assign to final name "NodeDigestMethod" - xmlsec.constants.NodeDigestValue = 'fizz' # E: Cannot assign to final name "NodeDigestValue" - xmlsec.constants.NodeEncryptedData = 'fizz' # E: Cannot assign to final name "NodeEncryptedData" - xmlsec.constants.NodeEncryptedKey = 'fizz' # E: Cannot assign to final name "NodeEncryptedKey" - xmlsec.constants.NodeEncryptionMethod = 'fizz' # E: Cannot assign to final name "NodeEncryptionMethod" - xmlsec.constants.NodeEncryptionProperties = 'fizz' # E: Cannot assign to final name "NodeEncryptionProperties" - xmlsec.constants.NodeEncryptionProperty = 'fizz' # E: Cannot assign to final name "NodeEncryptionProperty" - xmlsec.constants.NodeKeyInfo = 'fizz' # E: Cannot assign to final name "NodeKeyInfo" - xmlsec.constants.NodeKeyName = 'fizz' # E: Cannot assign to final name "NodeKeyName" - xmlsec.constants.NodeKeyReference = 'fizz' # E: Cannot assign to final name "NodeKeyReference" - xmlsec.constants.NodeKeyValue = 'fizz' # E: Cannot assign to final name "NodeKeyValue" - xmlsec.constants.NodeManifest = 'fizz' # E: Cannot assign to final name "NodeManifest" - xmlsec.constants.NodeObject = 'fizz' # E: Cannot assign to final name "NodeObject" - xmlsec.constants.NodeReference = 'fizz' # E: Cannot assign to final name "NodeReference" - xmlsec.constants.NodeReferenceList = 'fizz' # E: Cannot assign to final name "NodeReferenceList" - xmlsec.constants.NodeSignature = 'fizz' # E: Cannot assign to final name "NodeSignature" - xmlsec.constants.NodeSignatureMethod = 'fizz' # E: Cannot assign to final name "NodeSignatureMethod" - xmlsec.constants.NodeSignatureProperties = 'fizz' # E: Cannot assign to final name "NodeSignatureProperties" - xmlsec.constants.NodeSignatureValue = 'fizz' # E: Cannot assign to final name "NodeSignatureValue" - xmlsec.constants.NodeSignedInfo = 'fizz' # E: Cannot assign to final name "NodeSignedInfo" - xmlsec.constants.NodeX509Data = 'fizz' # E: Cannot assign to final name "NodeX509Data" - xmlsec.constants.Ns = 'fizz' # E: Cannot assign to final name "Ns" - xmlsec.constants.NsExcC14N = 'fizz' # E: Cannot assign to final name "NsExcC14N" - xmlsec.constants.NsExcC14NWithComments = 'fizz' # E: Cannot assign to final name "NsExcC14NWithComments" - xmlsec.constants.Soap11Ns = 'fizz' # E: Cannot assign to final name "Soap11Ns" - xmlsec.constants.Soap12Ns = 'fizz' # E: Cannot assign to final name "Soap12Ns" - xmlsec.constants.TransformAes128Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes128Cbc" - xmlsec.constants.TransformAes192Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes192Cbc" - xmlsec.constants.TransformAes256Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformAes256Cbc" - xmlsec.constants.TransformDes3Cbc = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformDes3Cbc" - xmlsec.constants.TransformDsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformDsaSha1" - xmlsec.constants.TransformEcdsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha1" - xmlsec.constants.TransformEcdsaSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha224" - xmlsec.constants.TransformEcdsaSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha256" - xmlsec.constants.TransformEcdsaSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha384" - xmlsec.constants.TransformEcdsaSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEcdsaSha512" - xmlsec.constants.TransformEnveloped = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformEnveloped" - xmlsec.constants.TransformExclC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformExclC14N" - xmlsec.constants.TransformExclC14NWithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformExclC14NWithComments" - xmlsec.constants.TransformHmacMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacMd5" - xmlsec.constants.TransformHmacRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacRipemd160" - xmlsec.constants.TransformHmacSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha1" - xmlsec.constants.TransformHmacSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha224" - xmlsec.constants.TransformHmacSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha256" - xmlsec.constants.TransformHmacSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha384" - xmlsec.constants.TransformHmacSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformHmacSha512" - xmlsec.constants.TransformInclC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N" - xmlsec.constants.TransformInclC14N11 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N11" - xmlsec.constants.TransformInclC14N11WithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14N11WithComments" - xmlsec.constants.TransformInclC14NWithComments = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformInclC14NWithComments" - xmlsec.constants.TransformKWAes128 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes128" - xmlsec.constants.TransformKWAes192 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes192" - xmlsec.constants.TransformKWAes256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWAes256" - xmlsec.constants.TransformKWDes3 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformKWDes3" - xmlsec.constants.TransformMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformMd5" - xmlsec.constants.TransformRemoveXmlTagsC14N = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRemoveXmlTagsC14N" - xmlsec.constants.TransformRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRipemd160" - xmlsec.constants.TransformRsaMd5 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaMd5" - xmlsec.constants.TransformRsaOaep = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaOaep" - xmlsec.constants.TransformRsaPkcs1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaPkcs1" - xmlsec.constants.TransformRsaRipemd160 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaRipemd160" - xmlsec.constants.TransformRsaSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha1" - xmlsec.constants.TransformRsaSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha224" - xmlsec.constants.TransformRsaSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha256" - xmlsec.constants.TransformRsaSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha384" - xmlsec.constants.TransformRsaSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformRsaSha512" - xmlsec.constants.TransformSha1 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha1" - xmlsec.constants.TransformSha224 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha224" - xmlsec.constants.TransformSha256 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha256" - xmlsec.constants.TransformSha384 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha384" - xmlsec.constants.TransformSha512 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformSha512" - xmlsec.constants.TransformUsageAny = -127 # E: Cannot assign to final name "TransformUsageAny" - xmlsec.constants.TransformUsageC14NMethod = -127 # E: Cannot assign to final name "TransformUsageC14NMethod" - xmlsec.constants.TransformUsageDSigTransform = -127 # E: Cannot assign to final name "TransformUsageDSigTransform" - xmlsec.constants.TransformUsageDigestMethod = -127 # E: Cannot assign to final name "TransformUsageDigestMethod" - xmlsec.constants.TransformUsageEncryptionMethod = -127 # E: Cannot assign to final name "TransformUsageEncryptionMethod" - xmlsec.constants.TransformUsageSignatureMethod = -127 # E: Cannot assign to final name "TransformUsageSignatureMethod" - xmlsec.constants.TransformUsageUnknown = -127 # E: Cannot assign to final name "TransformUsageUnknown" - xmlsec.constants.TransformVisa3DHack = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformVisa3DHack" - xmlsec.constants.TransformXPath = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPath" - xmlsec.constants.TransformXPath2 = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPath2" - xmlsec.constants.TransformXPointer = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXPointer" - xmlsec.constants.TransformXslt = xmlsec.constants.__Transform('', '', 0) # E: Cannot assign to final name "TransformXslt" - xmlsec.constants.TypeEncContent = 'fizz' # E: Cannot assign to final name "TypeEncContent" - xmlsec.constants.TypeEncElement = 'fizz' # E: Cannot assign to final name "TypeEncElement" - xmlsec.constants.XPath2Ns = 'fizz' # E: Cannot assign to final name "XPath2Ns" - xmlsec.constants.XPathNs = 'fizz' # E: Cannot assign to final name "XPathNs" - xmlsec.constants.XPointerNs = 'fizz' # E: Cannot assign to final name "XPointerNs" - -- case: primitive-constants-have-literal-types - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.DSigNs) # N: Revealed type is 'Literal['http://www.w3.org/2000/09/xmldsig#']?' - reveal_type(xmlsec.constants.EncNs) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#']?' - reveal_type(xmlsec.constants.KeyDataFormatBinary) # N: Revealed type is 'Literal[1]?' - reveal_type(xmlsec.constants.KeyDataFormatCertDer) # N: Revealed type is 'Literal[8]?' - reveal_type(xmlsec.constants.KeyDataFormatCertPem) # N: Revealed type is 'Literal[7]?' - reveal_type(xmlsec.constants.KeyDataFormatDer) # N: Revealed type is 'Literal[3]?' - reveal_type(xmlsec.constants.KeyDataFormatPem) # N: Revealed type is 'Literal[2]?' - reveal_type(xmlsec.constants.KeyDataFormatPkcs12) # N: Revealed type is 'Literal[6]?' - reveal_type(xmlsec.constants.KeyDataFormatPkcs8Der) # N: Revealed type is 'Literal[5]?' - reveal_type(xmlsec.constants.KeyDataFormatPkcs8Pem) # N: Revealed type is 'Literal[4]?' - reveal_type(xmlsec.constants.KeyDataFormatUnknown) # N: Revealed type is 'Literal[0]?' - reveal_type(xmlsec.constants.KeyDataTypeAny) # N: Revealed type is 'Literal[65535]?' - reveal_type(xmlsec.constants.KeyDataTypeNone) # N: Revealed type is 'Literal[0]?' - reveal_type(xmlsec.constants.KeyDataTypePermanent) # N: Revealed type is 'Literal[16]?' - reveal_type(xmlsec.constants.KeyDataTypePrivate) # N: Revealed type is 'Literal[2]?' - reveal_type(xmlsec.constants.KeyDataTypePublic) # N: Revealed type is 'Literal[1]?' - reveal_type(xmlsec.constants.KeyDataTypeSession) # N: Revealed type is 'Literal[8]?' - reveal_type(xmlsec.constants.KeyDataTypeSymmetric) # N: Revealed type is 'Literal[4]?' - reveal_type(xmlsec.constants.KeyDataTypeTrusted) # N: Revealed type is 'Literal[256]?' - reveal_type(xmlsec.constants.KeyDataTypeUnknown) # N: Revealed type is 'Literal[0]?' - reveal_type(xmlsec.constants.NodeCanonicalizationMethod) # N: Revealed type is 'Literal['CanonicalizationMethod']?' - reveal_type(xmlsec.constants.NodeCipherData) # N: Revealed type is 'Literal['CipherData']?' - reveal_type(xmlsec.constants.NodeCipherReference) # N: Revealed type is 'Literal['CipherReference']?' - reveal_type(xmlsec.constants.NodeCipherValue) # N: Revealed type is 'Literal['CipherValue']?' - reveal_type(xmlsec.constants.NodeDataReference) # N: Revealed type is 'Literal['DataReference']?' - reveal_type(xmlsec.constants.NodeDigestMethod) # N: Revealed type is 'Literal['DigestMethod']?' - reveal_type(xmlsec.constants.NodeDigestValue) # N: Revealed type is 'Literal['DigestValue']?' - reveal_type(xmlsec.constants.NodeEncryptedData) # N: Revealed type is 'Literal['EncryptedData']?' - reveal_type(xmlsec.constants.NodeEncryptedKey) # N: Revealed type is 'Literal['EncryptedKey']?' - reveal_type(xmlsec.constants.NodeEncryptionMethod) # N: Revealed type is 'Literal['EncryptionMethod']?' - reveal_type(xmlsec.constants.NodeEncryptionProperties) # N: Revealed type is 'Literal['EncryptionProperties']?' - reveal_type(xmlsec.constants.NodeEncryptionProperty) # N: Revealed type is 'Literal['EncryptionProperty']?' - reveal_type(xmlsec.constants.NodeKeyInfo) # N: Revealed type is 'Literal['KeyInfo']?' - reveal_type(xmlsec.constants.NodeKeyName) # N: Revealed type is 'Literal['KeyName']?' - reveal_type(xmlsec.constants.NodeKeyReference) # N: Revealed type is 'Literal['KeyReference']?' - reveal_type(xmlsec.constants.NodeKeyValue) # N: Revealed type is 'Literal['KeyValue']?' - reveal_type(xmlsec.constants.NodeManifest) # N: Revealed type is 'Literal['Manifest']?' - reveal_type(xmlsec.constants.NodeObject) # N: Revealed type is 'Literal['Object']?' - reveal_type(xmlsec.constants.NodeReference) # N: Revealed type is 'Literal['Reference']?' - reveal_type(xmlsec.constants.NodeReferenceList) # N: Revealed type is 'Literal['ReferenceList']?' - reveal_type(xmlsec.constants.NodeSignature) # N: Revealed type is 'Literal['Signature']?' - reveal_type(xmlsec.constants.NodeSignatureMethod) # N: Revealed type is 'Literal['SignatureMethod']?' - reveal_type(xmlsec.constants.NodeSignatureProperties) # N: Revealed type is 'Literal['SignatureProperties']?' - reveal_type(xmlsec.constants.NodeSignatureValue) # N: Revealed type is 'Literal['SignatureValue']?' - reveal_type(xmlsec.constants.NodeSignedInfo) # N: Revealed type is 'Literal['SignedInfo']?' - reveal_type(xmlsec.constants.NodeX509Data) # N: Revealed type is 'Literal['X509Data']?' - reveal_type(xmlsec.constants.Ns) # N: Revealed type is 'Literal['http://www.aleksey.com/xmlsec/2002']?' - reveal_type(xmlsec.constants.NsExcC14N) # N: Revealed type is 'Literal['http://www.w3.org/2001/10/xml-exc-c14n#']?' - reveal_type(xmlsec.constants.NsExcC14NWithComments) # N: Revealed type is 'Literal['http://www.w3.org/2001/10/xml-exc-c14n#WithComments']?' - reveal_type(xmlsec.constants.Soap11Ns) # N: Revealed type is 'Literal['http://schemas.xmlsoap.org/soap/envelope/']?' - reveal_type(xmlsec.constants.Soap12Ns) # N: Revealed type is 'Literal['http://www.w3.org/2002/06/soap-envelope']?' - reveal_type(xmlsec.constants.TransformUsageAny) # N: Revealed type is 'Literal[65535]?' - reveal_type(xmlsec.constants.TransformUsageC14NMethod) # N: Revealed type is 'Literal[2]?' - reveal_type(xmlsec.constants.TransformUsageDSigTransform) # N: Revealed type is 'Literal[1]?' - reveal_type(xmlsec.constants.TransformUsageDigestMethod) # N: Revealed type is 'Literal[4]?' - reveal_type(xmlsec.constants.TransformUsageEncryptionMethod) # N: Revealed type is 'Literal[16]?' - reveal_type(xmlsec.constants.TransformUsageSignatureMethod) # N: Revealed type is 'Literal[8]?' - reveal_type(xmlsec.constants.TransformUsageUnknown) # N: Revealed type is 'Literal[0]?' - reveal_type(xmlsec.constants.TypeEncContent) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#Content']?' - reveal_type(xmlsec.constants.TypeEncElement) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmlenc#Element']?' - reveal_type(xmlsec.constants.XPath2Ns) # N: Revealed type is 'Literal['http://www.w3.org/2002/06/xmldsig-filter2']?' - reveal_type(xmlsec.constants.XPathNs) # N: Revealed type is 'Literal['http://www.w3.org/TR/1999/REC-xpath-19991116']?' - reveal_type(xmlsec.constants.XPointerNs) # N: Revealed type is 'Literal['http://www.w3.org/2001/04/xmldsig-more/xptr']?' - -- case: transform-constants-href-attribute-has-type-string - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.TransformAes128Cbc.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformAes192Cbc.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformAes256Cbc.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformDes3Cbc.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformDsaSha1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha224.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha256.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha384.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha512.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEnveloped.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformExclC14N.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformExclC14NWithComments.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacMd5.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacRipemd160.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha224.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha256.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha384.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha512.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N11.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N11WithComments.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14NWithComments.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes128.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes192.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes256.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWDes3.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformMd5.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRipemd160.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaMd5.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaOaep.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaPkcs1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaRipemd160.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha224.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha256.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha384.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha512.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha1.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha224.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha256.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha384.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha512.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformVisa3DHack.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPath.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPath2.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPointer.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXslt.href) # N: Revealed type is 'builtins.str' - -- case: transform-constants-name-attribute-has-type-string - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.TransformAes128Cbc.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformAes192Cbc.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformAes256Cbc.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformDes3Cbc.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformDsaSha1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha224.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha256.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha384.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEcdsaSha512.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformEnveloped.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformExclC14N.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformExclC14NWithComments.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacMd5.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacRipemd160.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha224.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha256.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha384.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformHmacSha512.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N11.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14N11WithComments.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformInclC14NWithComments.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes128.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes192.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWAes256.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformKWDes3.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformMd5.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRipemd160.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaMd5.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaOaep.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaPkcs1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaRipemd160.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha224.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha256.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha384.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformRsaSha512.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha1.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha224.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha256.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha384.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformSha512.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformVisa3DHack.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPath.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPath2.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXPointer.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.TransformXslt.name) # N: Revealed type is 'builtins.str' - -- case: transform-constants-usage-attribute-has-type-int - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.TransformAes128Cbc.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformAes192Cbc.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformAes256Cbc.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformDes3Cbc.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformDsaSha1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEcdsaSha1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEcdsaSha224.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEcdsaSha256.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEcdsaSha384.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEcdsaSha512.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformEnveloped.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformExclC14N.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformExclC14NWithComments.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacMd5.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacRipemd160.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacSha1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacSha224.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacSha256.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacSha384.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformHmacSha512.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformInclC14N.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformInclC14N11.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformInclC14N11WithComments.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformInclC14NWithComments.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformKWAes128.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformKWAes192.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformKWAes256.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformKWDes3.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformMd5.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRemoveXmlTagsC14N.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRipemd160.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaMd5.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaOaep.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaPkcs1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaRipemd160.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaSha1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaSha224.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaSha256.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaSha384.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformRsaSha512.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformSha1.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformSha224.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformSha256.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformSha384.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformSha512.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformVisa3DHack.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformXPath.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformXPath2.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformXPointer.usage) # N: Revealed type is 'builtins.int' - reveal_type(xmlsec.constants.TransformXslt.usage) # N: Revealed type is 'builtins.int' - -- case: keydata-constants-name-attribute-has-type-string - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.KeyDataAes.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataDes.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataDsa.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataEcdsa.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataEncryptedKey.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataHmac.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataName.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRawX509Cert.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRetrievalMethod.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRsa.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataValue.name) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataX509.name) # N: Revealed type is 'builtins.str' - -- case: keydata-constants-href-attribute-has-type-string - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - reveal_type(xmlsec.constants.KeyDataAes.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataDes.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataDsa.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataEcdsa.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataEncryptedKey.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataHmac.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataName.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRawX509Cert.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRetrievalMethod.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataRsa.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataValue.href) # N: Revealed type is 'builtins.str' - reveal_type(xmlsec.constants.KeyDataX509.href) # N: Revealed type is 'builtins.str' diff --git a/tests/typesafe/test_xmlsec.yml b/tests/typesafe/test_xmlsec.yml deleted file mode 100644 index 9750d76a..00000000 --- a/tests/typesafe/test_xmlsec.yml +++ /dev/null @@ -1,57 +0,0 @@ -# all tests ignore import errors b/c mypy-testing-plugin -# can't resolve local stubs, see https://github.com/typeddjango/pytest-mypy-plugins/issues/17 -- case: module-functions-allowed-calls - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - xmlsec.enable_debug_trace() - xmlsec.enable_debug_trace(True) - xmlsec.enable_debug_trace(enabled=True) - xmlsec.enable_debug_trace(enabled=False) - xmlsec.init() - xmlsec.shutdown() - -- case: module-functions-disallowed-calls - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - xmlsec.enable_debug_trace('') # E: Argument 1 to "enable_debug_trace" has incompatible type "str"; expected "bool" - xmlsec.enable_debug_trace(None) # E: Argument 1 to "enable_debug_trace" has incompatible type "None"; expected "bool" - xmlsec.enable_debug_trace(1) # E: Argument 1 to "enable_debug_trace" has incompatible type "int"; expected "bool" - xmlsec.enable_debug_trace(enabled='') # E: Argument "enabled" to "enable_debug_trace" has incompatible type "str"; expected "bool" - xmlsec.enable_debug_trace(enabled=None) # E: Argument "enabled" to "enable_debug_trace" has incompatible type "None"; expected "bool" - xmlsec.enable_debug_trace(enabled=1) # E: Argument "enabled" to "enable_debug_trace" has incompatible type "int"; expected "bool" - -- case: encyption-context-init - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - ctx = xmlsec.EncryptionContext() - - mgr = xmlsec.KeysManager() - ctx = xmlsec.EncryptionContext(mgr) - ctx = xmlsec.EncryptionContext(manager=mgr) - ctx = xmlsec.EncryptionContext(None) - ctx = xmlsec.EncryptionContext(manager=None) - - ctx = xmlsec.EncryptionContext(True) # E: Argument 1 to "EncryptionContext" has incompatible type "bool"; expected "Optional[KeysManager]" - ctx = xmlsec.EncryptionContext('') # E: Argument 1 to "EncryptionContext" has incompatible type "str"; expected "Optional[KeysManager]" - ctx = xmlsec.EncryptionContext(1) # E: Argument 1 to "EncryptionContext" has incompatible type "int"; expected "Optional[KeysManager]" - ctx = xmlsec.EncryptionContext(manager=True) # E: Argument "manager" to "EncryptionContext" has incompatible type "bool"; expected "Optional[KeysManager]" - ctx = xmlsec.EncryptionContext(manager='') # E: Argument "manager" to "EncryptionContext" has incompatible type "str"; expected "Optional[KeysManager]" - ctx = xmlsec.EncryptionContext(manager=1) # E: Argument "manager" to "EncryptionContext" has incompatible type "int"; expected "Optional[KeysManager]" - -- case: encyption-context-attributes - mypy_config: - ignore_missing_imports = True - main: | - import xmlsec - ctx = xmlsec.EncryptionContext() - reveal_type(ctx.key) # N: Revealed type is 'xmlsec.Key' - ctx.key = None # E: Incompatible types in assignment (expression has type "None", variable has type "Key") - ctx.key = True # E: Incompatible types in assignment (expression has type "bool", variable has type "Key") - ctx.key = '' # E: Incompatible types in assignment (expression has type "str", variable has type "Key") - ctx.key = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Key") From 04ba05fe483b829bce06075bf9e88d0f76d24206 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 17 May 2020 23:42:53 +0200 Subject: [PATCH 155/378] update constants stub to fixes on master Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 10 +++++----- tests/test_type_stubs.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 4352b3b2..71b717a7 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -32,9 +32,9 @@ KeyDataFormatPkcs8Der: Final = 5 KeyDataFormatPkcs8Pem: Final = 4 KeyDataFormatUnknown: Final = 0 KeyDataHmac: Final = __KeyData('hmac', 'http://www.aleksey.com/xmlsec/2002#HMACKeyValue') -KeyDataName: Final = __KeyData('key-name', '(null)') +KeyDataName: Final = __KeyData('key-name', None) KeyDataRawX509Cert: Final = __KeyData('raw-x509-cert', 'http://www.w3.org/2000/09/xmldsig#rawX509Certificate') -KeyDataRetrievalMethod: Final = __KeyData('retrieval-method', '(null)') +KeyDataRetrievalMethod: Final = __KeyData('retrieval-method', None) KeyDataRsa: Final = __KeyData('rsa', 'http://www.w3.org/2000/09/xmldsig#RSAKeyValue') KeyDataTypeAny: Final = 65535 KeyDataTypeNone: Final = 0 @@ -45,7 +45,7 @@ KeyDataTypeSession: Final = 8 KeyDataTypeSymmetric: Final = 4 KeyDataTypeTrusted: Final = 256 KeyDataTypeUnknown: Final = 0 -KeyDataValue: Final = __KeyData('key-value', '(null)') +KeyDataValue: Final = __KeyData('key-value', None) KeyDataX509: Final = __KeyData('x509', 'http://www.w3.org/2000/09/xmldsig#X509Data') NodeCanonicalizationMethod: Final = 'CanonicalizationMethod' NodeCipherData: Final = 'CipherData' @@ -113,7 +113,7 @@ TransformKWAes192: Final = __Transform('kw-aes192', 'http://www.w3.org/2001/04/x TransformKWAes256: Final = __Transform('kw-aes256', 'http://www.w3.org/2001/04/xmlenc#kw-aes256', 16) TransformKWDes3: Final = __Transform('kw-tripledes', 'http://www.w3.org/2001/04/xmlenc#kw-tripledes', 16) TransformMd5: Final = __Transform('md5', 'http://www.w3.org/2001/04/xmldsig-more#md5', 4) -TransformRemoveXmlTagsC14N: Final = __Transform('remove-xml-tags-transform', '(null)', 3) +TransformRemoveXmlTagsC14N: Final = __Transform('remove-xml-tags-transform', None, 3) TransformRipemd160: Final = __Transform('ripemd160', 'http://www.w3.org/2001/04/xmlenc#ripemd160', 4) TransformRsaMd5: Final = __Transform('rsa-md5', 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5', 8) TransformRsaOaep: Final = __Transform('rsa-oaep-mgf1p', 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', 16) @@ -136,7 +136,7 @@ TransformUsageDigestMethod: Final = 4 TransformUsageEncryptionMethod: Final = 16 TransformUsageSignatureMethod: Final = 8 TransformUsageUnknown: Final = 0 -TransformVisa3DHack: Final = __Transform('Visa3DHackTransform', '(null)', 1) +TransformVisa3DHack: Final = __Transform('Visa3DHackTransform', None, 1) TransformXPath: Final = __Transform('xpath', 'http://www.w3.org/TR/1999/REC-xpath-19991116', 1) TransformXPath2: Final = __Transform('xpath2', 'http://www.w3.org/2002/06/xmldsig-filter2', 1) TransformXPointer: Final = __Transform('xpointer', 'http://www.w3.org/2001/04/xmldsig-more/xptr', 1) diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py index 8310615b..3b1c3757 100644 --- a/tests/test_type_stubs.py +++ b/tests/test_type_stubs.py @@ -21,9 +21,9 @@ from typing import NamedTuple if sys.version_info >= (3, 8): - from typing import Final, Literal + from typing import Final else: - from typing_extensions import Final, Literal + from typing_extensions import Final class __KeyData(NamedTuple): # __KeyData type From 46632deb7974bafb9923ec7b40af27236c1a26c8 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Mon, 18 May 2020 22:59:44 +0200 Subject: [PATCH 156/378] reexport child modules Signed-off-by: oleg.hoefling --- doc/source/examples/encrypt.py | 2 +- src/xmlsec/__init__.pyi | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/doc/source/examples/encrypt.py b/doc/source/examples/encrypt.py index 595b63c9..f69d4613 100644 --- a/doc/source/examples/encrypt.py +++ b/doc/source/examples/encrypt.py @@ -15,7 +15,7 @@ xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") -enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_OAEP) +enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.constants.TransformRsaOaep) xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) data = template.find('./Data') diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index eac54966..192d741c 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -3,6 +3,7 @@ from typing import AnyStr, IO, Iterable, Optional, Type, TypeVar, Union from lxml.etree import _Element +from xmlsec import constants, template, tree from xmlsec.constants import __KeyData as KeyData, __Transform as Transform if sys.version_info >= (3, 6): From 2c3f60ae27503c00d87633ee010ad6b2160ed6b8 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Mon, 18 May 2020 23:32:27 +0200 Subject: [PATCH 157/378] make key attribute optional in contexts, fix wrong autogenerated positional args Signed-off-by: oleg.hoefling --- src/xmlsec/__init__.pyi | 50 ++++++++++++++++++++--------------------- src/xmlsec/template.pyi | 46 ++++++++++++++++--------------------- src/xmlsec/tree.pyi | 14 ++++++------ 3 files changed, 50 insertions(+), 60 deletions(-) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 192d741c..540553c4 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -26,12 +26,12 @@ def init() -> None: ... def shutdown() -> None: ... class EncryptionContext: - key: Key + key: Optional[Key] def __init__(self, manager: Optional[KeysManager] = None) -> None: ... - def decrypt(self, node: _Element = ...) -> _Element: ... - def encrypt_binary(self, template: _E = ..., data: bytes = ...) -> _E: ... - def encrypt_uri(self, template: _E = ..., uri: str = ...) -> _E: ... - def encrypt_xml(self, template: _E = ..., node: _Element = ...) -> _E: ... + def decrypt(self, node: _Element) -> _Element: ... + def encrypt_binary(self, template: _E, data: bytes) -> _E: ... + def encrypt_uri(self, template: _E, uri: str) -> _E: ... + def encrypt_xml(self, template: _E, node: _Element) -> _E: ... def reset(self) -> None: ... class Error(Exception): ... @@ -40,36 +40,34 @@ class InternalError(Error): ... class Key: name: str @classmethod - def from_binary_data(cls: Type[_K], klass: KeyData = ..., data: AnyStr = ...) -> _K: ... + def from_binary_data(cls: Type[_K], klass: KeyData, data: AnyStr) -> _K: ... @classmethod - def from_binary_file(cls: Type[_K], klass: KeyData = ..., filename: _Path = ...) -> _K: ... + def from_binary_file(cls: Type[_K], klass: KeyData, filename: _Path) -> _K: ... @classmethod - def from_file( - cls: Type[_K], file: Union[_Path, IO[AnyStr]] = ..., format: int = ..., password: Optional[str] = ... - ) -> _K: ... + def from_file(cls: Type[_K], file: Union[_Path, IO[AnyStr]], format: int, password: Optional[str] = ...) -> _K: ... @classmethod - def from_memory(cls: Type[_K], data: AnyStr = ..., format: int = ..., password: Optional[str] = ...) -> _K: ... + def from_memory(cls: Type[_K], data: AnyStr, format: int, password: Optional[str] = ...) -> _K: ... @classmethod - def generate(cls: Type[_K], klass: KeyData = ..., size: int = ..., type: int = ...) -> _K: ... - def load_cert_from_file(self, file: Union[_Path, IO[AnyStr]] = ..., format: int = ...) -> None: ... - def load_cert_from_memory(self, data: AnyStr, format: int = ...) -> None: ... + def generate(cls: Type[_K], klass: KeyData, size: int, type: int) -> _K: ... + def load_cert_from_file(self, file: Union[_Path, IO[AnyStr]], format: int) -> None: ... + def load_cert_from_memory(self, data: AnyStr, format: int) -> None: ... def __copy__(self: _K) -> _K: ... def __deepcopy__(self: _K) -> _K: ... class KeysManager: - def add_key(self, key: Key = ...) -> None: ... - def load_cert(self, filename: _Path = ..., format: int = ..., type: int = ...) -> None: ... - def load_cert_from_memory(self, data: AnyStr = ..., format: int = ..., type: int = ...) -> None: ... + def add_key(self, key: Key) -> None: ... + def load_cert(self, filename: _Path, format: int, type: int) -> None: ... + def load_cert_from_memory(self, data: AnyStr, format: int, type: int) -> None: ... class SignatureContext: - key: Key - def enable_reference_transform(self, transform: Transform = ...) -> None: ... - def enable_signature_transform(self, transform: Transform = ...) -> None: ... - def register_id(self, node: _Element = ..., id_attr: str = "ID", id_ns: Optional[str] = None) -> None: ... - def set_enabled_key_data(self, keydata_list: Iterable[KeyData] = ...) -> None: ... - def sign(self, node: _Element = ...) -> None: ... - def sign_binary(self, bytes: bytes = ..., transform: Transform = ...) -> bytes: ... - def verify(self, node: _Element = ...) -> None: ... - def verify_binary(self, bytes: bytes = ..., transform: Transform = ..., signature: bytes = ...) -> None: ... + key: Optional[Key] + def enable_reference_transform(self, transform: Transform) -> None: ... + def enable_signature_transform(self, transform: Transform) -> None: ... + def register_id(self, node: _Element, id_attr: str = "ID", id_ns: Optional[str] = None) -> None: ... + def set_enabled_key_data(self, keydata_list: Iterable[KeyData]) -> None: ... + def sign(self, node: _Element) -> None: ... + def sign_binary(self, bytes: bytes, transform: Transform) -> bytes: ... + def verify(self, node: _Element) -> None: ... + def verify_binary(self, bytes: bytes, transform: Transform, signature: bytes) -> None: ... class VerificationError(Error): ... diff --git a/src/xmlsec/template.pyi b/src/xmlsec/template.pyi index 96ee3d0b..162fe25d 100644 --- a/src/xmlsec/template.pyi +++ b/src/xmlsec/template.pyi @@ -5,41 +5,33 @@ from lxml.etree import _Element from xmlsec.constants import __Transform as Transform def add_encrypted_key( - node: _Element = ..., - method: Transform = ..., - id: Optional[str] = None, - type: Optional[str] = None, - recipient: Optional[str] = None, + node: _Element, method: Transform, id: Optional[str] = None, type: Optional[str] = None, recipient: Optional[str] = None ) -> _Element: ... -def add_key_name(node: _Element = ..., name: Optional[str] = ...) -> _Element: ... -def add_key_value(node: _Element = ...) -> _Element: ... +def add_key_name(node: _Element, name: Optional[str] = ...) -> _Element: ... +def add_key_value(node: _Element) -> _Element: ... def add_reference( - node: _Element = ..., - digest_method: Transform = ..., - id: Optional[str] = ..., - uri: Optional[str] = ..., - type: Optional[str] = ..., + node: _Element, digest_method: Transform, id: Optional[str] = ..., uri: Optional[str] = ..., type: Optional[str] = ... ) -> _Element: ... -def add_transform(node: _Element = ..., transform: Transform = ...) -> Any: ... -def add_x509_data(node: _Element = ...) -> _Element: ... -def create(node: _Element = ..., c14n_method: Transform = ..., sign_method: Transform = ...) -> _Element: ... +def add_transform(node: _Element, transform: Transform) -> Any: ... +def add_x509_data(node: _Element) -> _Element: ... +def create(node: _Element, c14n_method: Transform, sign_method: Transform) -> _Element: ... def encrypted_data_create( - node: _Element = ..., - method: Transform = ..., + node: _Element, + method: Transform, id: Optional[str] = ..., type: Optional[str] = ..., mime_type: Optional[str] = ..., encoding: Optional[str] = ..., ns: Optional[str] = ..., ) -> _Element: ... -def encrypted_data_ensure_cipher_value(node: _Element = ...) -> _Element: ... +def encrypted_data_ensure_cipher_value(node: _Element) -> _Element: ... def encrypted_data_ensure_key_info(node: _Element, id: Optional[str] = ..., ns: Optional[str] = ...) -> _Element: ... -def ensure_key_info(node: _Element = ..., id: Optional[str] = ...) -> _Element: ... -def transform_add_c14n_inclusive_namespaces(node: _Element = ..., prefixes: Union[str, Sequence[str]] = ...) -> None: ... -def x509_data_add_certificate(node: _Element = ...) -> _Element: ... -def x509_data_add_crl(node: _Element = ...) -> _Element: ... -def x509_data_add_issuer_serial(node: _Element = ...) -> _Element: ... -def x509_data_add_ski(node: _Element = ...) -> _Element: ... -def x509_data_add_subject_name(node: _Element = ...) -> _Element: ... -def x509_issuer_serial_add_issuer_name(node: _Element = ..., name: Optional[str] = ...) -> _Element: ... -def x509_issuer_serial_add_serial_number(node: _Element = ..., serial: Optional[str] = ...) -> _Element: ... +def ensure_key_info(node: _Element, id: Optional[str] = ...) -> _Element: ... +def transform_add_c14n_inclusive_namespaces(node: _Element, prefixes: Union[str, Sequence[str]]) -> None: ... +def x509_data_add_certificate(node: _Element) -> _Element: ... +def x509_data_add_crl(node: _Element) -> _Element: ... +def x509_data_add_issuer_serial(node: _Element) -> _Element: ... +def x509_data_add_ski(node: _Element) -> _Element: ... +def x509_data_add_subject_name(node: _Element) -> _Element: ... +def x509_issuer_serial_add_issuer_name(node: _Element, name: Optional[str] = ...) -> _Element: ... +def x509_issuer_serial_add_serial_number(node: _Element, serial: Optional[str] = ...) -> _Element: ... diff --git a/src/xmlsec/tree.pyi b/src/xmlsec/tree.pyi index a416b001..6447fd08 100644 --- a/src/xmlsec/tree.pyi +++ b/src/xmlsec/tree.pyi @@ -2,16 +2,16 @@ from typing import Optional, overload, Sequence from lxml.etree import _Element -def add_ids(node: _Element = ..., ids: Sequence[str] = ...) -> None: ... +def add_ids(node: _Element, ids: Sequence[str]) -> None: ... @overload -def find_child(parent: _Element = ..., name: str = ...) -> Optional[_Element]: ... +def find_child(parent: _Element, name: str) -> Optional[_Element]: ... @overload -def find_child(parent: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... +def find_child(parent: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... @overload -def find_node(node: _Element = ..., name: str = ...) -> Optional[_Element]: ... +def find_node(node: _Element, name: str) -> Optional[_Element]: ... @overload -def find_node(node: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... +def find_node(node: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... @overload -def find_parent(node: _Element = ..., name: str = ...) -> Optional[_Element]: ... +def find_parent(node: _Element, name: str) -> Optional[_Element]: ... @overload -def find_parent(node: _Element = ..., name: str = ..., namespace: str = ...) -> Optional[_Element]: ... +def find_parent(node: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... From 860ea780d21d863192c4d950e226b6f2a22de775 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 20 May 2020 22:55:32 +0200 Subject: [PATCH 158/378] remove configuration for uploading dists to pypi since no permissions to store secrets Signed-off-by: oleg.hoefling --- .appveyor.yml | 14 -------------- .github/workflows/manylinux2010.yml | 10 ---------- 2 files changed, 24 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index d0c4d701..e3aee77a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,10 +1,4 @@ environment: - global: - TWINE_NON_INTERACTIVE: true - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_PASSWORD: - secure: YI+izt+hzh/czFuDCrne4cyTkNhdK/svjrWoIkN3nurz1LO1/YUb+zl8ln6hlMONaPhWLDI9YqmCobf3XdQVa8pclSCRiEtxg1HENmVOLJTS1IQCOMZhQjfXt5iNH5ov601/pgS367akiuGryGUoPkhcmJ9oD8aRH9dZ+Abh+PYPRMa3ka4U3SLcIHgzRUizLvkd73+Z5S4tjwjnDa1XHDnt/fZbeLjVL7T/4B2bWxnBVvHAckV/MGeOX3XgSK3UWdpEDTsg4ns0X0OubSziww== matrix: - python: 27 - python: 27-x64 @@ -31,11 +25,3 @@ test_script: - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - pytest -v --color=yes - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - -deploy: on -deploy_script: - - ps: >- - If ($env:APPVEYOR_REPO_TAG -eq $TRUE) { - pip install twine - twine upload dist/*.whl - } diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 7c677dd6..7d58279a 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -35,13 +35,3 @@ jobs: - name: Run tests run: | /opt/python/${{ matrix.python-abi }}/bin/pytest -v --color=yes - - name: Upload dist - if: startsWith(github.ref, 'refs/tags/') - env: - TWINE_NON_INTERACTIVE: true - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.pypi_token }} - run: | - /opt/python/${{ matrix.python-abi }}/bin/pip install twine - /opt/python/${{ matrix.python-abi }}/bin/twine upload wheelhouse/xmlsec-${PKGVER}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl From f65202ccfc668ab64b8f71879bd340b75d1031de Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 20 May 2020 23:02:27 +0200 Subject: [PATCH 159/378] also remove configuration for uploading sdist to pypi Signed-off-by: oleg.hoefling --- .github/workflows/sdist.yml | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index a6eda5bd..9c6e1282 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -24,13 +24,3 @@ jobs: - name: Run tests run: | pytest -v --color=yes - - name: Upload dist - if: startsWith(github.ref, 'refs/tags/') - env: - TWINE_NON_INTERACTIVE: true - TWINE_REPOSITORY_URL: https://test.pypi.org/legacy/ - TWINE_USERNAME: __token__ - TWINE_PASSWORD: ${{ secrets.pypi_token }} - run: | - pip install twine - twine upload dist/xmlsec-*.tar.gz From 9f88cab9bd89ef673292f95da10c20ace0225bdc Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 00:09:58 +0200 Subject: [PATCH 160/378] fix rst formatting issues in readme, remove python compat section, add link to docs Signed-off-by: oleg.hoefling --- README.rst | 172 ++++++++++++++++++++++++----------------------------- 1 file changed, 79 insertions(+), 93 deletions(-) diff --git a/README.rst b/README.rst index 24c3f991..6accae9b 100644 --- a/README.rst +++ b/README.rst @@ -15,26 +15,34 @@ python-xmlsec :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status -Python bindings for the XML Security Library. +Python bindings for the `XML Security Library `_. + +Documentation +************* + +A documentation for ``xmlsec`` can be found at `xmlsec.readthedocs.io `_. -****** Usage -****** +***** -Check the `examples `_ to see various examples of signing and verifying using the library. +Check the `examples `_ section in the documentation to see various examples of signing and verifying using the library. -************ Requirements ************ -- libxml2 >= 2.9.1 -- libxmlsec1 >= 1.2.14 +- ``libxml2 >= 2.9.1`` +- ``libxmlsec1 >= 1.2.18`` -******* Install ******* -Pre-Install ------------ +``xmlsec`` is available on PyPI: + +.. code-block:: bash + + pip install xmlsec + +Prerequisites +------------- Linux (Debian) ^^^^^^^^^^^^^^ @@ -44,15 +52,15 @@ Linux (Debian) apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl -Note: There is no required version of libxml2 for ubuntu precise, -so need to download and install it manually. +Note: There is no required version of LibXML2 for Ubuntu Precise, +so you need to download and install it manually. .. code-block:: bash - wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz - tar -xvf libxml2-2.9.1.tar.gz - cd libxml2-2.9.1 - ./configure && make && make install + wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz + tar -xvf libxml2-2.9.1.tar.gz + cd libxml2-2.9.1 + ./configure && make && make install Linux (CentOS) @@ -60,7 +68,7 @@ Linux (CentOS) .. code-block:: bash - yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel + yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel Mac @@ -68,7 +76,7 @@ Mac .. code-block:: bash - brew install libxml2 libxmlsec1 pkg-config + brew install libxml2 libxmlsec1 pkg-config Alpine @@ -76,73 +84,58 @@ Alpine .. code-block:: bash - apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec - - -Automated ---------- -1. **xmlsec** can be installed through `easy_install` or `pip`. - -.. code-block:: bash - - pip install xmlsec + apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec +Troubleshooting +--------------- Mac ^^^ -If you get any fatal errors about missing .h files, update your C_INCLUDE_PATH environment variable to -include the appropriate files from the libxml2 and libxmlsec1 libraries. - +If you get any fatal errors about missing ``.h`` files, update your +``C_INCLUDE_PATH`` environment variable to include the appropriate +files from the ``libxml2`` and ``libxmlsec1`` libraries. -Windows (Wheel) -^^^^^^^^^^^^^^^ -#. Download appropriate binary wheel from `ci.appveyor.com `_ (see build`s artifacts). +Windows +^^^^^^^ -#. Install wheel - - .. code-block:: bash - - pip install - - -Windows (pip) -^^^^^^^^^^^^^ +Starting with 1.3.7, prebuilt wheels are available for Windows, +so running ``pip install xmlsec`` should suffice. If you want +to build from source: #. Configure build environment, see `wiki.python.org `_ for more details. -#. Install from pip +#. Install from source dist: - .. code-block:: bash + .. code-block:: bash - pip install xmlsec + pip install xmlsec --no-binary=xmlsec -Manual ------- +Building from source +-------------------- -#. Clone the **xmlsec** repository to your local computer. +#. Clone the ``xmlsec`` repository to your local computer. - .. code-block:: bash + .. code-block:: bash - git clone git://github.com/mehcode/python-xmlsec.git + git clone https://github.com/mehcode/python-xmlsec.git -#. Change into the **xmlsec** root directory. +#. Change into the ``python-xmlsec`` root directory. - .. code-block:: bash + .. code-block:: bash - cd /path/to/xmlsec + cd /path/to/xmlsec -#. Install the project and all its dependencies using `pip`. +#. Install the project and all its dependencies using ``pip``. - .. code-block:: bash + .. code-block:: bash - pip install . + pip install . -************ Contributing ************ @@ -156,66 +149,59 @@ Setting up your environment This is done so as to ensure every contributor is working with close-to-identicial versions of packages. - .. code-block:: bash + .. code-block:: bash + + mkvirtualenv xmlsec + + The ``mkvirtualenv`` command is available from ``virtualenvwrapper`` package which can be installed by following `link `_. - mkvirtualenv xmlsec +#. Activate the created virtual environment: + .. code-block:: bash - The `mkvirtualenv` command is available from `virtualenvwrapper` which - can be installed by following `link `_ + workon xmlsec -#. Install **xmlsec** in development mode with testing enabled. +#. Install ``xmlsec`` in development mode with testing enabled. This will download all dependencies required for running the unit tests. - .. code-block:: bash + .. code-block:: bash - pip install -r requirements-test.txt - pip install -e "." + pip install -r requirements-test.txt + pip install -e "." Running the test suite ---------------------- -#. [Set up your environment](#setting-up-your-environment). +#. `Set up your environment <#setting-up-your-environment>`_. #. Run the unit tests. - .. code-block:: bash + .. code-block:: bash - py.test tests + pytest tests #. Tests configuration - Env variable **PYXMLSEC_TEST_ITERATIONS** specifies number of test iterations to detect memory leaks. -Reporting a issue ------------------ -Please attach the output of following information: -version of python-xmlsec -version of libxmlsec1 -version of libxml2 - -output from command: - -.. code-block:: bash + Env variable ``PYXMLSEC_TEST_ITERATIONS`` specifies number of + test iterations to detect memory leaks. - pkg-config --cflags xmlsec1 +Reporting an issue +------------------ +Please attach the output of following information: -****************** -Versions of python -****************** +* version of ``xmlsec`` +* version of ``libxmlsec1`` +* version of ``libxml2`` +* output from the command -The following versions of python is supported: + .. code-block:: bash - - python2.7 - - python3.4 - - python3.5 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) - - python3.6 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) - - python3.7 (required libxmlsec1 >= 1.2.18 and libxml2 >= 2.9.1) + pkg-config --cflags xmlsec1 -******* License ******* -Unless otherwise noted, all files contained within this project are liensed under the MIT opensource license. -See the included file LICENSE or visit `opensource.org `_ for more information. +Unless otherwise noted, all files contained within this project are licensed under the MIT opensource license. +See the included ``LICENSE`` file or visit `opensource.org `_ for more information. From 5472a7923f9088d4b6d431a69b2efc03d3615838 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 00:10:54 +0200 Subject: [PATCH 161/378] include readme in package metadata Signed-off-by: oleg.hoefling --- setup.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 962114cd..d555c19c 100644 --- a/setup.py +++ b/setup.py @@ -1,3 +1,4 @@ +import io import multiprocessing import os import subprocess @@ -11,7 +12,6 @@ from setuptools.command.build_ext import build_ext as build_ext_orig if sys.version_info >= (3, 4): - from pathlib import Path from urllib.request import urlcleanup, urljoin, urlretrieve else: from urllib import urlcleanup, urlretrieve @@ -397,6 +397,8 @@ def prepare_static_build_linux(self): if sys.version_info >= (3, 4): + from pathlib import Path + src_root = Path(__file__).parent / 'src' sources = [str(p.absolute()) for p in src_root.rglob('*.c')] else: @@ -415,10 +417,15 @@ def prepare_static_build_linux(self): setup_reqs.append('pathlib2') +with io.open('README.rst', encoding='utf-8') as f: + long_desc = f.read() + + setup( name='xmlsec', use_scm_version=True, description='Python bindings for the XML Security Library', + long_description=long_desc, ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, setup_requires=setup_reqs, From 7b3af1461be063ee2936b1022fc46369a679490d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 00:12:53 +0200 Subject: [PATCH 162/378] restrict supported python versions through package metadata Signed-off-by: oleg.hoefling --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index d555c19c..68542db8 100644 --- a/setup.py +++ b/setup.py @@ -428,6 +428,7 @@ def prepare_static_build_linux(self): long_description=long_desc, ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, + python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', setup_requires=setup_reqs, install_requires=['lxml>=3.8'], author="Bulat Gaifullin", From 825f2c66f14621b6dbeab12527fc9a8a9327046a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 00:42:05 +0200 Subject: [PATCH 163/378] update installation notes in docs Signed-off-by: oleg.hoefling --- README.rst | 27 ++++++++----- doc/source/install.rst | 86 ++++++++++++++++++++++++++---------------- 2 files changed, 72 insertions(+), 41 deletions(-) diff --git a/README.rst b/README.rst index 6accae9b..374cb6d0 100644 --- a/README.rst +++ b/README.rst @@ -41,8 +41,8 @@ Install pip install xmlsec -Prerequisites -------------- +Depending on your OS, you may need to install the required native +libraries first: Linux (Debian) ^^^^^^^^^^^^^^ @@ -71,6 +71,14 @@ Linux (CentOS) yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel +Linux (Fedora) +^^^^^^^^^^^^^^ + +.. code-block:: bash + + dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel + + Mac ^^^ @@ -86,8 +94,9 @@ Alpine apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec + Troubleshooting ---------------- +*************** Mac ^^^ @@ -114,9 +123,9 @@ to build from source: Building from source --------------------- +******************** -#. Clone the ``xmlsec`` repository to your local computer. +#. Clone the ``xmlsec`` source code repository to your local computer. .. code-block:: bash @@ -140,9 +149,9 @@ Contributing ************ Setting up your environment ---------------------------- +^^^^^^^^^^^^^^^^^^^^^^^^^^^ -#. Follow steps 1 and 2 of the `manual installation instructions <#manual>`_. +#. Follow steps 1 and 2 of the `manual installation instructions <#building-from-source>`_. #. Initialize a virtual environment to develop in. @@ -171,7 +180,7 @@ Setting up your environment Running the test suite ----------------------- +^^^^^^^^^^^^^^^^^^^^^^ #. `Set up your environment <#setting-up-your-environment>`_. @@ -187,7 +196,7 @@ Running the test suite test iterations to detect memory leaks. Reporting an issue ------------------- +^^^^^^^^^^^^^^^^^^ Please attach the output of following information: diff --git a/doc/source/install.rst b/doc/source/install.rst index 57107c75..834b9acb 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -1,67 +1,89 @@ -Install ------------ +Installation +============ -Linux (Debian) -^^^^^^^^^^^^^^ +``xmlsec`` is available on PyPI: .. code-block:: bash - apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl - pip install xmlsec + pip install xmlsec +Depending on your OS, you may need to install the required native +libraries first: -Note: There is no required version of libxml2 for ubuntu precise, -so need to download and install it manually. +Linux (Debian) +-------------- .. code-block:: bash - wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz - tar -xvf libxml2-2.9.1.tar.gz - cd libxml2-2.9.1 - ./configure && make && make install + apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl + +.. note:: There is no required version of LibXML2 for Ubuntu Precise, + so you need to download and install it manually: + + .. code-block:: bash + + wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz + tar -xvf libxml2-2.9.1.tar.gz + cd libxml2-2.9.1 + ./configure && make && make install Linux (CentOS) -^^^^^^^^^^^^^^ +-------------- .. code-block:: bash - yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel - pip install xmlsec + yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel + + +Linux (Fedora) +-------------- + +.. code-block:: bash + + dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel Mac -^^^ +--- .. code-block:: bash - xcode-select --install - brew upgrade - brew install libxml2 libxmlsec1 pkg-config - pip install xmlsec + xcode-select --install + brew upgrade + brew install libxml2 libxmlsec1 pkg-config +Alpine +------ -Windows (Wheel) -^^^^^^^^^^^^^^^ +.. code-block:: bash -#. Download appropriate binary wheels from `appveyor `_ (see build`s artifacts). + apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec -#. Install downloaded wheel - .. code-block:: bash +Troubleshooting +*************** - pip install +Mac +--- +If you get any fatal errors about missing ``.h`` files, update your +``C_INCLUDE_PATH`` environment variable to include the appropriate +files from the ``libxml2`` and ``libxmlsec1`` libraries. -Windows (pip) -^^^^^^^^^^^^^ -#. Configure build environment, see `wiki.python.org `_ for more details. +Windows +------- + +Starting with 1.3.7, prebuilt wheels are available for Windows, +so running ``pip install xmlsec`` should suffice. If you want +to build from source: -#. Install from pip +#. Configure build environment, see `wiki.python.org `_ for more details. - .. code-block:: bash +#. Install from source dist: - pip install xmlsec + .. code-block:: bash + pip install xmlsec --no-binary=xmlsec From b80100ddd4797f5f95b14b088547d8be81d79f63 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 01:05:50 +0200 Subject: [PATCH 164/378] add github actions for macos Signed-off-by: oleg.hoefling --- .github/workflows/macosx.yml | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 .github/workflows/macosx.yml diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml new file mode 100644 index 00000000..daf2c3dd --- /dev/null +++ b/.github/workflows/macosx.yml @@ -0,0 +1,28 @@ +name: MacOS +on: [push, pull_request] +jobs: + macosx: + runs-on: macos-latest + strategy: + matrix: + python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + steps: + - uses: actions/checkout@v1 + - name: Install build dependencies + run: | + pip install --upgrade pip setuptools wheel + brew install libxml2 libxmlsec1 pkg-config + - name: Set environment variables + shell: bash + run: | + echo ::set-env name=PKGVER::$(python setup.py --version) + - name: Build macosx_x86_64 wheel + run: | + python setup.py bdist_wheel + - name: Install test dependencies + run: | + pip install --upgrade -r requirements-test.txt + pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + - name: Run tests + run: | + pytest -v --color=yes From ff834612bebf55df945d10436cd9997c62166353 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 01:22:41 +0200 Subject: [PATCH 165/378] add macos badge Signed-off-by: oleg.hoefling --- README.rst | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.rst b/README.rst index 374cb6d0..b58c518b 100644 --- a/README.rst +++ b/README.rst @@ -7,6 +7,8 @@ python-xmlsec :target: https://ci.appveyor.com/project/hoefling/xmlsec .. image:: https://github.com/mehcode/python-xmlsec/workflows/manylinux2010/badge.svg :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 +.. image:: https://github.com/mehcode/python-xmlsec/workflows/MacOS/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22MacOS%22 .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg From 50ec2d9ac34cc4946c975971df97d12f94da9877 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 11:14:07 +0200 Subject: [PATCH 166/378] escape the XMSLEC_CRYPTO macro value, just as it was done in the original setup Signed-off-by: oleg.hoefling --- setup.py | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/setup.py b/setup.py index 68542db8..6906174d 100644 --- a/setup.py +++ b/setup.py @@ -75,6 +75,12 @@ def run(self): ext.define_macros.extend( [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] ) + # escape the XMLSEC_CRYPTO macro value, see mehcode/python-xmlsec#141 + for (key, value) in ext.define_macros: + if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')): + ext.define_macros.remove((key, value)) + ext.define_macros.append((key, '"{0}"'.format(value))) + break if sys.platform == 'win32': ext.extra_compile_args.append('/Zi') From 14c276fb6ba7bc8cf4307ba21b4de346608aa511 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 21:19:00 +0200 Subject: [PATCH 167/378] require recent pkgconfig to avoid pytest dependency conflicts Signed-off-by: oleg.hoefling --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 6906174d..d3739f76 100644 --- a/setup.py +++ b/setup.py @@ -417,7 +417,7 @@ def prepare_static_build_linux(self): sources.append(os.path.join(root, file)) pyxmlsec = Extension('xmlsec', sources=sources) -setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig', 'lxml>=3.8'] +setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] if sys.version_info < (3, 4): setup_reqs.append('pathlib2') From 6e62c074086fdcadfb952873dab4ac2ca95840fa Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 23 May 2020 14:22:41 +0200 Subject: [PATCH 168/378] set up correct python version on macos Signed-off-by: oleg.hoefling --- .github/workflows/macosx.yml | 6 +++++- .github/workflows/sdist.yml | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index daf2c3dd..a7e42b70 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,9 +5,13 @@ jobs: runs-on: macos-latest strategy: matrix: - python-version: [2.7, 3.5, 3.6, 3.7, 3.8] + python: [2.7, 3.5, 3.6, 3.7, 3.8] steps: - uses: actions/checkout@v1 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 9c6e1282..9a7a4b4e 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -6,7 +6,7 @@ jobs: steps: - uses: actions/checkout@v1 - name: Set up Python 3.8 - uses: actions/setup-python@v1 + uses: actions/setup-python@v2 with: python-version: 3.8 - name: Install build dependencies From 096dd0c8865b1da68a97919d96c46dbe536a3dbc Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 24 May 2020 22:44:25 +0200 Subject: [PATCH 169/378] new function to set default max columns size for base64 encoding Signed-off-by: oleg.hoefling --- src/main.c | 35 +++++++++++++++++++++++++++++++++++ src/xmlsec/__init__.pyi | 6 +++++- tests/test_main.py | 32 ++++++++++++++++++++++++++++++++ 3 files changed, 72 insertions(+), 1 deletion(-) create mode 100644 tests/test_main.py diff --git a/src/main.c b/src/main.c index 85f457f2..b1f49180 100644 --- a/src/main.c +++ b/src/main.c @@ -14,6 +14,7 @@ #include #include #include +#include #define _PYXMLSEC_FREE_NONE 0 #define _PYXMLSEC_FREE_XMLSEC 1 @@ -127,6 +128,34 @@ static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, Py Py_RETURN_NONE; } +static char PyXmlSec_PyBase64DefaultLineSize__doc__[] = \ + "base64_default_line_size(size = None)\n" + "Configures the default maximum columns size for base64 encoding.\n\n" + "If ``size`` is not given, this function returns the current default size, acting as a getter. " + "If ``size`` is given, a new value is applied and this function returns nothing, acting as a setter.\n" + ":param size: new default size value (optional)\n" + ":type size: :class:`int` or :data:`None`"; +static PyObject* PyXmlSec_PyBase64DefaultLineSize(PyObject *self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { "size", NULL }; + PyObject *pySize = NULL; + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:base64_default_line_size", kwlist, &pySize)) { + return NULL; + } + if (pySize == NULL) { + return PyLong_FromLong(xmlSecBase64GetDefaultLineSize()); + } + int size = (int)PyLong_AsLong(pySize); + if (PyErr_Occurred()) { + return NULL; + } + if (size < 0) { + PyErr_SetString(PyExc_ValueError, "size must be positive"); + return NULL; + } + xmlSecBase64SetDefaultLineSize(size); + Py_RETURN_NONE; +} + static PyMethodDef PyXmlSec_MainMethods[] = { { "init", @@ -146,6 +175,12 @@ static PyMethodDef PyXmlSec_MainMethods[] = { METH_VARARGS|METH_KEYWORDS, PyXmlSec_PyEnableDebugOutput__doc__ }, + { + "base64_default_line_size", + (PyCFunction)PyXmlSec_PyBase64DefaultLineSize, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_PyBase64DefaultLineSize__doc__ + }, {NULL, NULL} /* sentinel */ }; diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 540553c4..9ec147e9 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,5 +1,5 @@ import sys -from typing import AnyStr, IO, Iterable, Optional, Type, TypeVar, Union +from typing import AnyStr, IO, Iterable, Optional, Type, TypeVar, Union, overload from lxml.etree import _Element @@ -24,6 +24,10 @@ _K = TypeVar('_K', bound=Key) def enable_debug_trace(enabled: bool = ...) -> None: ... def init() -> None: ... def shutdown() -> None: ... +@overload +def base64_default_line_size() -> int: ... +@overload +def base64_default_line_size(size: int) -> None: ... class EncryptionContext: key: Optional[Key] diff --git a/tests/test_main.py b/tests/test_main.py new file mode 100644 index 00000000..a0d144ca --- /dev/null +++ b/tests/test_main.py @@ -0,0 +1,32 @@ +import xmlsec +from tests import base + + +class TestBase64LineSize(base.TestMemoryLeaks): + def tearDown(self): + xmlsec.base64_default_line_size(64) + super(TestBase64LineSize, self).tearDown() + + def test_get_base64_default_line_size(self): + self.assertEqual(xmlsec.base64_default_line_size(), 64) + + def test_set_base64_default_line_size_positional_arg(self): + xmlsec.base64_default_line_size(0) + self.assertEqual(xmlsec.base64_default_line_size(), 0) + + def test_set_base64_default_line_size_keyword_arg(self): + xmlsec.base64_default_line_size(size=0) + self.assertEqual(xmlsec.base64_default_line_size(), 0) + + def test_set_base64_default_line_size_with_bad_args(self): + size = xmlsec.base64_default_line_size() + for bad_size in (None, '', object()): + with self.assertRaises(TypeError): + xmlsec.base64_default_line_size(bad_size) + self.assertEqual(xmlsec.base64_default_line_size(), size) + + def test_set_base64_default_line_size_rejects_negative_values(self): + size = xmlsec.base64_default_line_size() + with self.assertRaises(ValueError): + xmlsec.base64_default_line_size(-1) + self.assertEqual(xmlsec.base64_default_line_size(), size) From 7c73b28e6d332a14d3fce4ada754e54d01ed539d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Mon, 25 May 2020 11:48:10 +0200 Subject: [PATCH 170/378] add source and documentation urls to package metadata Signed-off-by: oleg.hoefling --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index d3739f76..10590135 100644 --- a/setup.py +++ b/setup.py @@ -442,6 +442,7 @@ def prepare_static_build_linux(self): maintainer='Oleg Hoefling', maintainer_email='oleg.hoefling@gmail.com', url='https://github.com/mehcode/python-xmlsec', + project_urls={'Documentation': 'https://xmlsec.readthedocs.io', 'Source': 'https://github.com/mehcode/python-xmlsec',}, license='MIT', keywords=['xmlsec'], classifiers=[ From 5531e0943d6e535db57a31a36c93cb9bef7edb06 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 28 May 2020 11:37:21 +0200 Subject: [PATCH 171/378] record and report code coverage in macosx jobs Signed-off-by: oleg.hoefling --- .github/workflows/macosx.yml | 24 ++++++++++++++++++------ 1 file changed, 18 insertions(+), 6 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index a7e42b70..02c778d4 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -16,17 +16,29 @@ jobs: run: | pip install --upgrade pip setuptools wheel brew install libxml2 libxmlsec1 pkg-config + - name: Build macosx_x86_64 wheel + run: | + python setup.py bdist_wheel - name: Set environment variables shell: bash run: | echo ::set-env name=PKGVER::$(python setup.py --version) - - name: Build macosx_x86_64 wheel - run: | - python setup.py bdist_wheel + echo ::set-env name=LLVM_PROFILE_FILE::"pyxmlsec-%p.profraw" - name: Install test dependencies + env: + CC: clang + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" + LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" run: | - pip install --upgrade -r requirements-test.txt - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + rm -rf build/ + pip install coverage --upgrade -r requirements-test.txt + pip install --editable . - name: Run tests run: | - pytest -v --color=yes + coverage run -m pytest -v --color=yes + - name: Report coverage to codecov + run: | + LIBFILE=$(python -c "import xmlsec; print(xmlsec.__file__)") + /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse pyxmlsec-*.profraw -output pyxmlsec.profdata + /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${LIBFILE} -instr-profile=pyxmlsec.profdata src > coverage.txt + bash <(curl -s https://codecov.io/bash) -f coverage.txt From 75cc6c093d323e672728fdd830ebb868f838c4f1 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 28 May 2020 14:21:59 +0200 Subject: [PATCH 172/378] also use codecov bash uploader in travis jobs since codecov-python has more issues to resolve Signed-off-by: oleg.hoefling --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index b5738884..4e9aa228 100644 --- a/.travis.yml +++ b/.travis.yml @@ -35,14 +35,14 @@ addons: - lcov install: - travis_retry pip install --upgrade pip setuptools wheel -- travis_retry pip install coverage codecov -r requirements-test.txt --upgrade --force-reinstall +- travis_retry pip install coverage -r requirements-test.txt --upgrade --force-reinstall - travis_retry pip install -e "." - pip list script: coverage run -m pytest -v tests --color=yes after_success: - lcov --capture --directory . --output-file coverage.info - lcov --list coverage.info -- codecov --file coverage.info +- bash <(curl -s https://codecov.io/bash) -f coverage.info before_deploy: - travis_retry pip install Sphinx -r doc/source/requirements.txt - git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff From f3bcec9aaa2ea49ea901b2fadfaf40b13db3772d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 28 May 2020 16:36:10 +0200 Subject: [PATCH 173/378] initialize size at the beginning of the function Signed-off-by: oleg.hoefling --- src/main.c | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index b1f49180..59989529 100644 --- a/src/main.c +++ b/src/main.c @@ -138,13 +138,14 @@ static char PyXmlSec_PyBase64DefaultLineSize__doc__[] = \ static PyObject* PyXmlSec_PyBase64DefaultLineSize(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { "size", NULL }; PyObject *pySize = NULL; + int size; if (!PyArg_ParseTupleAndKeywords(args, kwargs, "|O:base64_default_line_size", kwlist, &pySize)) { return NULL; } if (pySize == NULL) { return PyLong_FromLong(xmlSecBase64GetDefaultLineSize()); } - int size = (int)PyLong_AsLong(pySize); + size = (int)PyLong_AsLong(pySize); if (PyErr_Occurred()) { return NULL; } From 0624740220430ee9a15aa930e4e72ea9a96e85d7 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 28 May 2020 16:42:53 +0200 Subject: [PATCH 174/378] publish test results in appveyor jobs Signed-off-by: oleg.hoefling --- .appveyor.yml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index e3aee77a..939d8d30 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -23,5 +23,12 @@ test: off test_script: - pip install -r requirements-test.txt - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - - pytest -v --color=yes + - pytest -v --color=yes --junitxml=unittests.xml - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } + +on_finish: + - ps: | + # archive test results at AppVeyor + $wc = New-Object 'System.Net.WebClient' + $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\unittests.xml)) + $LastExitCode = 0 From 2f62ff74614909d69440fe7fef53b299890e9fd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Fri, 29 May 2020 22:59:29 +0200 Subject: [PATCH 175/378] Increase test coverage (#144) Work towards 100% code coverage in unit tests, fix segfaults encountered --- .travis.yml | 2 +- src/ds.c | 11 +++ src/enc.c | 11 ++- src/keys.c | 13 +++- tests/base.py | 3 + tests/conftest.py | 10 +++ tests/test_ds.py | 146 +++++++++++++++++++++++++++++++++++++-- tests/test_enc.py | 136 +++++++++++++++++++++++++++++++++--- tests/test_keys.py | 98 ++++++++++++++++++++++++-- tests/test_templates.py | 148 +++++++++++++++++++++++++++++----------- tests/test_tree.py | 20 +++++- tests/test_xmlsec.py | 14 ++++ 12 files changed, 548 insertions(+), 64 deletions(-) create mode 100644 tests/conftest.py create mode 100644 tests/test_xmlsec.py diff --git a/.travis.yml b/.travis.yml index 4e9aa228..2abd7f82 100644 --- a/.travis.yml +++ b/.travis.yml @@ -40,7 +40,7 @@ install: - pip list script: coverage run -m pytest -v tests --color=yes after_success: -- lcov --capture --directory . --output-file coverage.info +- lcov --capture --no-external --directory . --output-file coverage.info - lcov --list coverage.info - bash <(curl -s https://codecov.io/bash) -f coverage.info before_deploy: diff --git a/src/ds.c b/src/ds.c index 43d3d118..d0b4bdf9 100644 --- a/src/ds.c +++ b/src/ds.c @@ -87,11 +87,21 @@ static int PyXmlSec_SignatureContextKeySet(PyObject* self, PyObject* value, void PyXmlSec_Key* key; PYXMLSEC_DEBUGF("%p, %p", self, value); + + if (value == NULL) { // key deletion + if (ctx->handle->signKey != NULL) { + xmlSecKeyDestroy(ctx->handle->signKey); + ctx->handle->signKey = NULL; + } + return 0; + } + if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); return -1; } key = (PyXmlSec_Key*)value; + if (key->handle == NULL) { PyErr_SetString(PyExc_TypeError, "empty key."); return -1; @@ -252,6 +262,7 @@ static int PyXmlSec_ProcessSignBinary(PyXmlSec_SignatureContext* ctx, const xmlS if (ctx->handle->signKey == NULL) { PyErr_SetString(PyXmlSec_Error, "Sign key is not specified."); + return -1; } if (ctx->handle->signMethod != NULL) { diff --git a/src/enc.c b/src/enc.c index 02c01d8a..aaf35ae5 100644 --- a/src/enc.c +++ b/src/enc.c @@ -90,6 +90,15 @@ static int PyXmlSec_EncryptionContextKeySet(PyObject* self, PyObject* value, voi PyXmlSec_Key* key; PYXMLSEC_DEBUGF("%p, %p", self, value); + + if (value == NULL) { // key deletion + if (ctx->handle->encKey != NULL) { + xmlSecKeyDestroy(ctx->handle->encKey); + ctx->handle->encKey = NULL; + } + return 0; + } + if (!PyObject_IsInstance(value, (PyObject*)PyXmlSec_KeyType)) { PyErr_SetString(PyExc_TypeError, "instance of *xmlsec.Key* expected."); return -1; @@ -224,7 +233,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptXml(PyObject* self, PyObject* } tmpType = xmlGetProp(template->_c_node, XSTR("Type")); if (tmpType == NULL || !(xmlStrEqual(tmpType, xmlSecTypeEncElement) || xmlStrEqual(tmpType, xmlSecTypeEncContent))) { - PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`)"); + PyErr_SetString(PyXmlSec_Error, "unsupported `Type`, it should be `element` or `content`"); goto ON_FAIL; } diff --git a/src/keys.c b/src/keys.c index 7fd080a1..357cc9c7 100644 --- a/src/keys.c +++ b/src/keys.c @@ -452,10 +452,21 @@ static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { return -1; } + if (value == NULL) { + if (xmlSecKeySetName(key->handle, value) < 0) { + PyXmlSec_SetLastError("cannot delete name"); + return -1; + } + return 0; + } + name = PyString_AsString(value); if (name == NULL) return -1; - xmlSecKeySetName(key->handle, XSTR(name)); + if (xmlSecKeySetName(key->handle, XSTR(name)) < 0) { + PyXmlSec_SetLastError("cannot set name"); + return -1; + } return 0; } diff --git a/tests/base.py b/tests/base.py index b05de1de..cf659b61 100644 --- a/tests/base.py +++ b/tests/base.py @@ -7,6 +7,9 @@ import unittest +if sys.version_info < (3, ): + unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp + etype = type(etree.Element("test")) diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 00000000..b51c4d45 --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,10 @@ +def pytest_collection_modifyitems(items): + """ + Put the module init test first to implicitly check whether + any subsequent test fails because of module reinitialization. + """ + + def module_init_tests_first(item): + return int('test_xmlsec.py::TestModule::test_reinitialize_module' not in item.nodeid) + + items.sort(key=module_init_tests_first) diff --git a/tests/test_ds.py b/tests/test_ds.py index 26d49075..cf49ee71 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -1,7 +1,5 @@ -from tests import base - import xmlsec - +from tests import base consts = xmlsec.constants @@ -11,18 +9,69 @@ def test_init(self): ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) del ctx - def test_key(self): + def test_init_no_keys_manager(self): + ctx = xmlsec.SignatureContext() + del ctx + + def test_init_bad_args(self): + with self.assertRaisesRegex(TypeError, 'KeysManager required'): + xmlsec.SignatureContext(manager='foo') + + def test_no_key(self): ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) self.assertIsNone(ctx.key) + + def test_del_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + del ctx.key + self.assertIsNone(ctx.key) + + def test_set_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) + def test_set_key_bad_type(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + with self.assertRaisesRegex(TypeError, r'instance of \*xmlsec.Key\* expected.'): + ctx.key = '' + + def test_set_invalid_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + with self.assertRaisesRegex(TypeError, 'empty key.'): + ctx.key = xmlsec.Key() + def test_register_id(self): ctx = xmlsec.SignatureContext() root = self.load_xml("sign_template.xml") sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id") ctx.register_id(sign, "Id") + def test_register_id_bad_args(self): + ctx = xmlsec.SignatureContext() + with self.assertRaises(TypeError): + ctx.register_id('') + + def test_register_id_with_namespace_without_attribute(self): + ctx = xmlsec.SignatureContext() + root = self.load_xml("sign_template.xml") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id") + with self.assertRaisesRegex(xmlsec.Error, 'missing attribute.'): + ctx.register_id(sign, "Id", id_ns='foo') + + def test_sign_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.sign('') + + def test_sign_fail(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(xmlsec.InternalError, 'failed to sign'): + ctx.sign(self.load_xml('sign1-in.xml')) + def test_sign_case1(self): """Should sign a pre-constructed template file using a key from a PEM file.""" root = self.load_xml("sign1-in.xml") @@ -134,6 +183,23 @@ def test_sign_case5(self): ctx.sign(sign) self.assertEqual(self.load_xml("sign5-out.xml"), root) + def test_sign_binary_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.sign_binary(bytes=1, transform='') + + def test_sign_binary_no_key(self): + ctx = xmlsec.SignatureContext() + with self.assertRaisesRegex(xmlsec.Error, 'Sign key is not specified.'): + ctx.sign_binary(bytes=b'', transform=consts.TransformRsaSha1) + + def test_sign_binary_invalid_signature_method(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(xmlsec.Error, 'incompatible signature method'): + ctx.sign_binary(bytes=b'', transform=consts.TransformXslt) + def test_sign_binary(self): ctx = xmlsec.SignatureContext() ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) @@ -144,6 +210,26 @@ def test_sign_binary(self): sign = ctx.sign_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1) self.assertEqual(self.load("sign6-out.bin"), sign) + def test_sign_binary_twice_not_possible(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + data = self.load('sign6-in.bin') + ctx.sign_binary(data, consts.TransformRsaSha1) + with self.assertRaisesRegex(xmlsec.Error, 'Signature context already used; it is designed for one use only.'): + ctx.sign_binary(data, consts.TransformRsaSha1) + + def test_verify_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.verify('') + + def test_verify_fail(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(xmlsec.InternalError, 'failed to verify'): + ctx.verify(self.load_xml('sign1-in.xml')) + def test_verify_case_1(self): self.check_verify(1) @@ -191,3 +277,55 @@ def test_validate_binary_sign_fail(self): self.assertEqual("rsakey.pem", ctx.key.name) with self.assertRaises(xmlsec.Error): ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, b"invalid") + + def test_enable_reference_transform(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.enable_reference_transform(consts.TransformRsaSha1) + + def test_enable_reference_transform_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.enable_reference_transform('') + with self.assertRaises(TypeError): + ctx.enable_reference_transform(0) + with self.assertRaises(TypeError): + ctx.enable_reference_transform(consts.KeyDataAes) + + def test_enable_signature_transform(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.enable_signature_transform(consts.TransformRsaSha1) + + def test_enable_signature_transform_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.enable_signature_transform('') + with self.assertRaises(TypeError): + ctx.enable_signature_transform(0) + with self.assertRaises(TypeError): + ctx.enable_signature_transform(consts.KeyDataAes) + + def test_set_enabled_key_data(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.set_enabled_key_data([consts.KeyDataAes]) + + def test_set_enabled_key_data_empty(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.set_enabled_key_data([]) + + def test_set_enabled_key_data_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + with self.assertRaises(TypeError): + ctx.set_enabled_key_data(0) + + def test_set_enabled_key_data_bad_list(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(TypeError, 'expected list of KeyData constants.'): + ctx.set_enabled_key_data('foo') diff --git a/tests/test_enc.py b/tests/test_enc.py index 2f8c9d74..141e5753 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -1,7 +1,10 @@ -from tests import base +import os +import tempfile -import xmlsec +from lxml import etree +import xmlsec +from tests import base consts = xmlsec.constants @@ -11,17 +14,48 @@ def test_init(self): ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) del ctx - def test_key(self): + def test_init_no_keys_manager(self): + ctx = xmlsec.EncryptionContext() + del ctx + + def test_init_bad_args(self): + with self.assertRaisesRegex(TypeError, 'KeysManager required'): + xmlsec.EncryptionContext(manager='foo') + + def test_no_key(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + self.assertIsNone(ctx.key) + + def test_get_key(self): ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) self.assertIsNone(ctx.key) ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) self.assertIsNotNone(ctx.key) + def test_del_key(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + del ctx.key + self.assertIsNone(ctx.key) + + def test_set_key(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + self.assertIsNotNone(ctx.key) + + def test_set_key_bad_type(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + with self.assertRaisesRegex(TypeError, r'instance of \*xmlsec.Key\* expected.'): + ctx.key = '' + + def test_set_invalid_key(self): + ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) + with self.assertRaisesRegex(TypeError, 'empty key.'): + ctx.key = xmlsec.Key() + def test_encrypt_xml(self): root = self.load_xml('enc1-in.xml') - enc_data = xmlsec.template.encrypted_data_create( - root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns="xenc" - ) + enc_data = xmlsec.template.encrypted_data_create(root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns="xenc") xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) @@ -49,6 +83,30 @@ def test_encrypt_xml(self): cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) self.assertIsNotNone(cipher_value) + def test_encrypt_xml_bad_args(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaises(TypeError): + ctx.encrypt_xml('', 0) + + def test_encrypt_xml_bad_template(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaisesRegex(xmlsec.Error, 'unsupported `Type`, it should be `element` or `content`'): + ctx.encrypt_xml(etree.Element('root'), etree.Element('node')) + + def test_encrypt_xml_bad_template_bad_type_attribute(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaisesRegex(xmlsec.Error, 'unsupported `Type`, it should be `element` or `content`'): + root = etree.Element('root') + root.attrib['Type'] = 'foo' + ctx.encrypt_xml(root, etree.Element('node')) + + def test_encrypt_xml_fail(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt xml'): + root = etree.Element('root') + root.attrib['Type'] = consts.TypeEncElement + ctx.encrypt_xml(root, etree.Element('node')) + def test_encrypt_binary(self): root = self.load_xml('enc2-in.xml') enc_data = xmlsec.template.encrypted_data_create( @@ -81,6 +139,61 @@ def test_encrypt_binary(self): cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) self.assertIsNotNone(cipher_value) + def test_encrypt_binary_bad_args(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaises(TypeError): + ctx.encrypt_binary('', 0) + + def test_encrypt_binary_bad_template(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt binary'): + ctx.encrypt_binary(etree.Element('root'), b'data') + + def test_encrypt_uri(self): + root = self.load_xml('enc2-in.xml') + enc_data = xmlsec.template.encrypted_data_create( + root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream" + ) + xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) + xmlsec.template.encrypted_data_ensure_cipher_value(ek) + + manager = xmlsec.KeysManager() + manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + + ctx = xmlsec.EncryptionContext(manager) + ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) + + with tempfile.NamedTemporaryFile(delete=False) as tmpfile: + tmpfile.write(b'test') + + encrypted = ctx.encrypt_binary(enc_data, 'file://' + tmpfile.name) + self.assertIsNotNone(encrypted) + self.assertEqual("{%s}%s" % (consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + + enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + + ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) + self.assertIsNotNone(ki) + enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) + self.assertIsNotNone(enc_method2) + self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) + self.assertIsNotNone(cipher_value) + + def test_encrypt_uri_bad_args(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaises(TypeError): + ctx.encrypt_uri('', 0) + + def test_encrypt_uri_fail(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaisesRegex(xmlsec.InternalError, 'failed to encrypt URI'): + ctx.encrypt_uri(etree.Element('root'), '') + def test_decrypt1(self): self.check_decrypt(1) @@ -117,18 +230,21 @@ def check_decrypt(self, i): self.assertIsNotNone(decrypted) self.assertEqual(self.load_xml("enc%d-in.xml" % i), root) + def test_decrypt_bad_args(self): + ctx = xmlsec.EncryptionContext() + with self.assertRaises(TypeError): + ctx.decrypt('') def check_no_segfault(self): - namespaces = { - 'soap': 'http://schemas.xmlsoap.org/soap/envelope/' - } + namespaces = {'soap': 'http://schemas.xmlsoap.org/soap/envelope/'} manager = xmlsec.KeysManager() key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) manager.add_key(key) template = self.load_xml('enc-bad-in.xml') enc_data = xmlsec.template.encrypted_data_create( - template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns='xenc') + template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns='xenc' + ) xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_PKCS1) diff --git a/tests/test_keys.py b/tests/test_keys.py index add11e41..12b8224f 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -1,9 +1,8 @@ -from tests import base - import copy +import tempfile import xmlsec - +from tests import base consts = xmlsec.constants @@ -17,6 +16,10 @@ def test_key_from_memory_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.from_memory(1, format="") + def test_key_from_memory_invalid_data(self): + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load key.*'): + xmlsec.Key.from_memory(b'foo', format=consts.KeyDataFormatPem) + def test_key_from_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) @@ -25,11 +28,23 @@ def test_key_from_file_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.from_file(1, format="") + def test_key_from_invalid_file(self): + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + with tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + xmlsec.Key.from_file(tmpfile.name, format=consts.KeyDataFormatPem) + def test_key_from_fileobj(self): with open(self.path("rsakey.pem"), "rb") as fobj: key = xmlsec.Key.from_file(fobj, format=consts.KeyDataFormatPem) self.assertIsNotNone(key) + def test_key_from_invalid_fileobj(self): + with tempfile.NamedTemporaryFile(delete=False) as tmpfile: + tmpfile.write(b'foo') + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'), open(tmpfile.name) as fp: + xmlsec.Key.from_file(fp, format=consts.KeyDataFormatPem) + def test_generate(self): key = xmlsec.Key.generate(klass=consts.KeyDataAes, size=256, type=consts.KeyDataTypeSession) self.assertIsNotNone(key) @@ -38,6 +53,10 @@ def test_generate_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.generate(klass="", size="", type="") + def test_generate_invalid_size(self): + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot generate key.*'): + xmlsec.Key.generate(klass=consts.KeyDataAes, size=0, type=consts.KeyDataTypeSession) + def test_from_binary_file(self): key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path("deskey.bin")) self.assertIsNotNone(key) @@ -46,6 +65,12 @@ def test_from_binary_file_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.from_binary_file(klass="", filename=1) + def test_from_invalid_binary_file(self): + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + with tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=tmpfile.name) + def test_from_binary_data(self): key = xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=self.load("deskey.bin")) self.assertIsNotNone(key) @@ -54,6 +79,10 @@ def test_from_binary_data_with_bad_args(self): with self.assertRaises(TypeError): xmlsec.Key.from_binary_data(klass="", data=1) + def test_from_invalid_binary_data(self): + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=b'') + def test_load_cert_from_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) @@ -65,12 +94,34 @@ def test_load_cert_from_file_with_bad_args(self): with self.assertRaises(TypeError): key.load_cert_from_file(1, format="") + def test_load_cert_from_invalid_file(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + key.load_cert_from_file(tmpfile.name, format=consts.KeyDataFormatPem) + def test_load_cert_from_fileobj(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) with open(self.path("rsacert.pem"), "rb") as fobj: key.load_cert_from_file(fobj, format=consts.KeyDataFormatPem) + def test_load_cert_from_fileobj_with_bad_args(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with self.assertRaises(TypeError), open(self.path("rsacert.pem"), "rb") as fobj: + key.load_cert_from_file(fobj, format='') + + def test_load_cert_from_invalid_fileobj(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with tempfile.NamedTemporaryFile(delete=False) as tmpfile: + tmpfile.write(b'foo') + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'), open(tmpfile.name) as fp: + key.load_cert_from_file(fp, format=consts.KeyDataFormatPem) + def test_load_cert_from_memory(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) @@ -82,12 +133,37 @@ def test_load_cert_from_memory_with_bad_args(self): with self.assertRaises(TypeError): key.load_cert_from_memory(1, format="") - def test_name(self): + def test_load_cert_from_memory_invalid_data(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNotNone(key) + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + key.load_cert_from_memory(b'', format=consts.KeyDataFormatPem) + + def test_get_name(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + self.assertIsNone(key.name) + + def test_get_name_invalid_key(self): + key = xmlsec.Key() + with self.assertRaisesRegex(ValueError, 'key is not ready'): + key.name + + def test_del_name(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key.name = "rsakey" + del key.name self.assertIsNone(key.name) + + def test_set_name(self): + key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) key.name = "rsakey" self.assertEqual("rsakey", key.name) + def test_set_name_invalid_key(self): + key = xmlsec.Key() + with self.assertRaisesRegex(ValueError, 'key is not ready'): + key.name = 'foo' + def test_copy(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) key2 = copy.copy(key) @@ -112,6 +188,14 @@ def test_load_cert(self): mngr.load_cert(self.path("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) def test_load_cert_with_bad_args(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + mngr.load_cert(tmpfile.name, format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + + def test_load_invalid_cert(self): mngr = xmlsec.KeysManager() mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) with self.assertRaises(TypeError): @@ -128,6 +212,12 @@ def test_load_cert_from_memory_with_bad_args(self): with self.assertRaises(TypeError): mngr.load_cert_from_memory(1, format="", type="") + def test_load_cert_from_memory_invalid_data(self): + mngr = xmlsec.KeysManager() + mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + mngr.load_cert_from_memory(b'', format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + def test_load_invalid_key(self): mngr = xmlsec.KeysManager() with self.assertRaises(ValueError): diff --git a/tests/test_templates.py b/tests/test_templates.py index dcd8d940..947e0bbc 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -1,7 +1,7 @@ -from tests import base +from lxml import etree import xmlsec - +from tests import base consts = xmlsec.constants @@ -10,20 +10,19 @@ class TestTemplates(base.TestMemoryLeaks): def test_create(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create( - root, - c14n_method=consts.TransformExclC14N, - sign_method=consts.TransformRsaSha1, - id="Id", - ns="test" + root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1, id="Id", ns="test" ) self.assertEqual("Id", sign.get("Id")) self.assertEqual("test", sign.prefix) + def test_create_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.create('', c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + def test_encrypt_data_create(self): root = self.load_xml("doc.xml") enc = xmlsec.template.encrypted_data_create( - root, method=consts.TransformDes3Cbc, id="Id", type="Type", mime_type="MimeType", encoding="Encoding", - ns="test" + root, method=consts.TransformDes3Cbc, id="Id", type="Type", mime_type="MimeType", encoding="Encoding", ns="test" ) for a in ("Id", "Type", "MimeType", "Encoding"): self.assertEqual(a, enc.get(a)) @@ -35,18 +34,21 @@ def test_ensure_key_info(self): ki = xmlsec.template.ensure_key_info(sign, id="Id") self.assertEqual("Id", ki.get("Id")) + def test_ensure_key_info_fail(self): + with self.assertRaisesRegex(xmlsec.InternalError, 'cannot ensure key info.'): + xmlsec.template.ensure_key_info(etree.fromstring(b''), id="Id") + + def test_ensure_key_info_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.ensure_key_info('', id=0) + def test_add_encrypted_key(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) - self.assertEqual( - ek, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeEncryptedKey, consts.EncNs) - ) - ek2 = xmlsec.template.add_encrypted_key( - ki, consts.TransformRsaOaep, id="Id", type="Type", recipient="Recipient" - ) + self.assertEqual(ek, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeEncryptedKey, consts.EncNs)) + ek2 = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep, id="Id", type="Type", recipient="Recipient") for a in ("Id", "Type", "Recipient"): self.assertEqual(a, ek2.get(a)) @@ -55,13 +57,22 @@ def test_add_key_name(self): sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) kn = xmlsec.template.add_key_name(ki) - self.assertEqual( - kn, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyName, consts.DSigNs) - ) + self.assertEqual(kn, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyName, consts.DSigNs)) kn2 = xmlsec.template.add_key_name(ki, name="name") self.assertEqual("name", kn2.text) + def test_add_key_name_none(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + ki = xmlsec.template.ensure_key_info(sign) + kn2 = xmlsec.template.add_key_name(ki, name=None) + self.assertEqual(kn2.text, None) + print(etree.tostring(kn2)) + + def test_add_key_name_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_key_name('') + def test_add_reference(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) @@ -69,15 +80,32 @@ def test_add_reference(self): for a in ("Id", "URI", "Type"): self.assertEqual(a, ref.get(a)) + def test_add_reference_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_reference('', consts.TransformSha1) + with self.assertRaises(TypeError): + xmlsec.template.add_reference(etree.Element('root'), '') + + def test_add_reference_fail(self): + with self.assertRaisesRegex(xmlsec.InternalError, 'cannot add reference.'): + xmlsec.template.add_reference(etree.Element('root'), consts.TransformSha1) + + def test_add_transform_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_transform('', consts.TransformSha1) + with self.assertRaises(TypeError): + xmlsec.template.add_transform(etree.Element('root'), '') + def test_add_key_value(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) kv = xmlsec.template.add_key_value(ki) - self.assertEqual( - kv, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyValue, consts.DSigNs) - ) + self.assertEqual(kv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyValue, consts.DSigNs)) + + def test_add_key_value_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_key_value('') def test_add_x509_data(self): root = self.load_xml("doc.xml") @@ -91,10 +119,11 @@ def test_add_x509_data(self): xmlsec.template.x509_data_add_subject_name(x509) xmlsec.template.x509_issuer_serial_add_issuer_name(issuer) xmlsec.template.x509_issuer_serial_add_serial_number(issuer) - self.assertEqual( - x509, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeX509Data, consts.DSigNs) - ) + self.assertEqual(x509, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeX509Data, consts.DSigNs)) + + def test_add_x509_data_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_x509_data('') def test_x509_issuer_serial_add_issuer(self): root = self.load_xml("doc.xml") @@ -107,27 +136,65 @@ def test_x509_issuer_serial_add_issuer(self): self.assertEqual("Name", name.text) self.assertEqual("Serial", serial.text) + def test_x509_issuer_serial_add_issuer_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_data_add_issuer_serial('') + + def test_x509_issuer_serial_add_issuer_name_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_issuer_serial_add_issuer_name('') + + def test_x509_issuer_serial_add_serial_number_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_issuer_serial_add_serial_number('') + + def test_x509_data_add_subject_name_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_data_add_subject_name('') + + def test_x509_data_add_ski_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_data_add_ski('') + + def test_x509_data_add_certificate_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_data_add_certificate('') + + def test_x509_data_add_crl_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.x509_data_add_crl('') + + def test_add_encrypted_key_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.add_encrypted_key('', 0) + + def test_encrypted_data_create_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.encrypted_data_create('', 0) + def test_encrypted_data_ensure_cipher_value(self): root = self.load_xml("doc.xml") enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) cv = xmlsec.template.encrypted_data_ensure_cipher_value(enc) - self.assertEqual( - cv, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeCipherValue, consts.EncNs) - ) + self.assertEqual(cv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeCipherValue, consts.EncNs)) + + def test_encrypted_data_ensure_cipher_value_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.encrypted_data_ensure_cipher_value('') def test_encrypted_data_ensure_key_info(self): root = self.load_xml("doc.xml") enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) ki = xmlsec.template.encrypted_data_ensure_key_info(enc) - self.assertEqual( - ki, - xmlsec.tree.find_node(self.load_xml("enc_template.xml"), consts.NodeKeyInfo, consts.DSigNs) - ) + self.assertEqual(ki, xmlsec.tree.find_node(self.load_xml("enc_template.xml"), consts.NodeKeyInfo, consts.DSigNs)) ki2 = xmlsec.template.encrypted_data_ensure_key_info(enc, id="Id", ns="test") self.assertEqual("Id", ki2.get("Id")) self.assertEqual("test", ki2.prefix) + def test_encrypted_data_ensure_key_info_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.encrypted_data_ensure_key_info('') + def test_transform_add_c14n_inclusive_namespaces(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) @@ -136,7 +203,8 @@ def test_transform_add_c14n_inclusive_namespaces(self): xmlsec.template.transform_add_c14n_inclusive_namespaces(trans1, "default") trans2 = xmlsec.template.add_transform(ref, consts.TransformXslt) xmlsec.template.transform_add_c14n_inclusive_namespaces(trans2, ["ns1", "ns2"]) - self.assertEqual( - ref, - xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeReference, consts.DSigNs) - ) + self.assertEqual(ref, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeReference, consts.DSigNs)) + + def test_transform_add_c14n_inclusive_namespaces_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.template.transform_add_c14n_inclusive_namespaces('', []) diff --git a/tests/test_tree.py b/tests/test_tree.py index f07c654c..4c79c8de 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -1,7 +1,5 @@ -from tests import base - import xmlsec - +from tests import base consts = xmlsec.constants @@ -14,18 +12,34 @@ def test_find_child(self): self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeReference)) self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.EncNs)) + def test_find_child_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.tree.find_child('', 0, True) + def test_find_parent(self): root = self.load_xml("sign_template.xml") si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs) self.assertIs(root, xmlsec.tree.find_parent(si, consts.NodeSignature)) self.assertIsNone(xmlsec.tree.find_parent(root, consts.NodeSignedInfo)) + def test_find_parent_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.tree.find_parent('', 0, True) + def test_find_node(self): root = self.load_xml("sign_template.xml") ref = xmlsec.tree.find_node(root, consts.NodeReference) self.assertEqual(consts.NodeReference, ref.tag.partition('}')[2]) self.assertIsNone(xmlsec.tree.find_node(root, consts.NodeReference, consts.EncNs)) + def test_find_node_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.tree.find_node('', 0, True) + def test_add_ids(self): root = self.load_xml("sign_template.xml") xmlsec.tree.add_ids(root, ["id1", "id2", "id3"]) + + def test_add_ids_bad_args(self): + with self.assertRaises(TypeError): + xmlsec.tree.add_ids('', []) diff --git a/tests/test_xmlsec.py b/tests/test_xmlsec.py new file mode 100644 index 00000000..32fac69a --- /dev/null +++ b/tests/test_xmlsec.py @@ -0,0 +1,14 @@ +import xmlsec +from tests import base + + +class TestModule(base.TestMemoryLeaks): + def test_reinitialize_module(self): + """ + This doesn't explicitly test anything, but will + be invoked first in the suite, so if the subsequent + tests don't fail, we know that the ``init()``/``shutdown()`` + function pair doesn't break anything. + """ + xmlsec.shutdown() + xmlsec.init() From 39c3bca3ce0ea55a8b29ce8a0999bfb4a72abb64 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Wed, 10 Jun 2020 17:51:35 +0100 Subject: [PATCH 176/378] add custom prefix to environment variables in setup script (#153) Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 +- .github/workflows/sdist.yml | 2 +- setup.py | 18 +++++++++--------- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 7d58279a..7ed19a5c 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -18,7 +18,7 @@ jobs: echo ::set-env name=PKGVER::$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version) - name: Build linux_x86_64 wheel env: - STATIC_DEPS: true + PYXMLSEC_STATIC_DEPS: true run: | /opt/python/${{ matrix.python-abi }}/bin/python setup.py bdist_wheel - name: Label manylinux2010_x86_64 wheel diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 9a7a4b4e..281cdaf9 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -17,7 +17,7 @@ jobs: python setup.py sdist - name: Install test dependencies env: - STATIC_DEPS: true + PYXMLSEC_STATIC_DEPS: true run: | pip install --upgrade -r requirements-test.txt pip install dist/xmlsec-$(python setup.py --version).tar.gz diff --git a/setup.py b/setup.py index 10590135..976489c6 100644 --- a/setup.py +++ b/setup.py @@ -29,8 +29,8 @@ def run(self): from pathlib2 import Path ext = self.ext_map['xmlsec'] - self.debug = os.environ.get('DEBUG', False) - self.static = os.environ.get('STATIC_DEPS', False) + self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) + self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) if self.static or sys.platform == 'win32': self.info('starting static build on {}'.format(sys.platform)) @@ -43,7 +43,7 @@ def run(self): self.build_libs_dir = buildroot / 'libs' self.build_libs_dir.mkdir(exist_ok=True) - self.libs_dir = Path(os.environ.get('LIBS_DIR', 'libs')) + self.libs_dir = Path(os.environ.get('PYXMLSEC_LIBS_DIR', 'libs')) self.libs_dir.mkdir(exist_ok=True) if sys.platform == 'win32': @@ -180,12 +180,12 @@ def prepare_static_build_win(self): ext.include_dirs = [str(p.absolute()) for p in includes] def prepare_static_build_linux(self): - self.openssl_version = os.environ.get('OPENSSL_VERSION', '1.1.1g') - self.libiconv_version = os.environ.get('LIBICONV_VERSION', '1.16') - self.libxml2_version = os.environ.get('LIBXML2_VERSION', None) - self.libxslt_version = os.environ.get('LIBXLST_VERSION', None) - self.zlib_version = os.environ.get('ZLIB_VERSION', '1.2.11') - self.xmlsec1_version = os.environ.get('XMLSEC1_VERSION', '1.2.30') + self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1g') + self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION', '1.16') + self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', None) + self.libxslt_version = os.environ.get('PYXMLSEC_LIBXLST_VERSION', None) + self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.2.11') + self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.2.30') self.info('Settings:') self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) From 78958c8096a00f01c2a84a4bf7084a2d1fb04352 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 21 May 2020 21:36:04 +0200 Subject: [PATCH 177/378] add aes-gcm transforms Signed-off-by: oleg.hoefling --- src/constants.c | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/constants.c b/src/constants.c index 02f5250c..68f086e9 100644 --- a/src/constants.c +++ b/src/constants.c @@ -543,6 +543,12 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha384, "SHA384"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha512, "SHA512"); +#if XMLSEC_VERSION_HEX > 315 + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes128Gcm, "AES128_GCM"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes192Gcm, "AES192_GCM"); + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes256Gcm, "AES256_GCM"); +#endif + PYXMLSEC_CLOSE_NAMESPACE(transformCls); #undef PYXMLSEC_ADD_TRANSFORM_CONSTANT From 2a6cd997c53d56c3128aa603d4c7bef28d5dd6e8 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 2 Jul 2020 17:12:42 +0200 Subject: [PATCH 178/378] add typing constants Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 71b717a7..8be27b23 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -79,8 +79,11 @@ NsExcC14NWithComments: Final = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComme Soap11Ns: Final = 'http://schemas.xmlsoap.org/soap/envelope/' Soap12Ns: Final = 'http://www.w3.org/2002/06/soap-envelope' TransformAes128Cbc: Final = __Transform('aes128-cbc', 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 16) +TransformAes128Gcm: Final = __Transform('aes128-gcm', 'http://www.w3.org/2009/xmlenc11#aes128-gcm', 16) TransformAes192Cbc: Final = __Transform('aes192-cbc', 'http://www.w3.org/2001/04/xmlenc#aes192-cbc', 16) +TransformAes192Gcm: Final = __Transform('aes192-gcm', 'http://www.w3.org/2009/xmlenc11#aes192-gcm', 16) TransformAes256Cbc: Final = __Transform('aes256-cbc', 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', 16) +TransformAes256Gcm: Final = __Transform('aes256-gcm', 'http://www.w3.org/2009/xmlenc11#aes256-gcm', 16) TransformDes3Cbc: Final = __Transform('tripledes-cbc', 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc', 16) TransformDsaSha1: Final = __Transform('dsa-sha1', 'http://www.w3.org/2000/09/xmldsig#dsa-sha1', 8) TransformEcdsaSha1: Final = __Transform('ecdsa-sha1', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1', 8) From 658001ef77ea7086c8391f2e0409072ed5bb9c60 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 2 Jul 2020 17:13:35 +0200 Subject: [PATCH 179/378] use badges with logo from shields.io Signed-off-by: oleg.hoefling --- README.rst | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/README.rst b/README.rst index b58c518b..f01d467d 100644 --- a/README.rst +++ b/README.rst @@ -1,9 +1,11 @@ python-xmlsec ============= -.. image:: https://travis-ci.org/mehcode/python-xmlsec.png?branch=master +.. image:: https://img.shields.io/pypi/v/xmlsec.svg?logo=python&logoColor=white + :target: https://pypi.python.org/pypi/xmlsec +.. image:: https://img.shields.io/travis/com/mehcode/python-xmlsec/master.svg?logo=travis&logoColor=white&label=Travis%20CI :target: https://travis-ci.org/mehcode/python-xmlsec -.. image:: https://ci.appveyor.com/api/projects/status/ij87xk5wo8a39jua?svg=true +.. image:: https://img.shields.io/appveyor/ci/hoefling/xmlsec/master.svg?logo=appveyor&logoColor=white&label=AppVeyor :target: https://ci.appveyor.com/project/hoefling/xmlsec .. image:: https://github.com/mehcode/python-xmlsec/workflows/manylinux2010/badge.svg :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 @@ -11,9 +13,7 @@ python-xmlsec :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22MacOS%22 .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg :target: https://codecov.io/gh/mehcode/python-xmlsec -.. image:: https://img.shields.io/pypi/v/xmlsec.svg - :target: https://pypi.python.org/pypi/xmlsec -.. image:: https://readthedocs.org/projects/xmlsec/badge/?version=latest +.. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status From ff32478725e80643b3ce0087665e55f0c9988b35 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 29 Oct 2020 13:51:26 +0100 Subject: [PATCH 180/378] add python 3.9 jobs Signed-off-by: oleg.hoefling --- .appveyor.yml | 2 ++ .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux2010.yml | 2 +- .github/workflows/sdist.yml | 4 ++-- .travis.yml | 2 +- 5 files changed, 7 insertions(+), 5 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 939d8d30..d945472a 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -10,6 +10,8 @@ environment: - python: 37-x64 - python: 38 - python: 38-x64 + - python: 39 + - python: 39-x64 install: - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 02c778d4..c8bfee95 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [2.7, 3.5, 3.6, 3.7, 3.8] + python: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v1 - name: Setup Python diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 7ed19a5c..637983d4 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -6,7 +6,7 @@ jobs: container: quay.io/pypa/manylinux2010_x86_64 strategy: matrix: - python-abi: [cp27-cp27m, cp27-cp27mu, cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38] + python-abi: [cp27-cp27m, cp27-cp27mu, cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] steps: - uses: actions/checkout@v1 - name: Install build dependencies diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 281cdaf9..5b5dac96 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -5,10 +5,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v1 - - name: Set up Python 3.8 + - name: Set up Python 3.9 uses: actions/setup-python@v2 with: - python-version: 3.8 + python-version: 3.9 - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel diff --git a/.travis.yml b/.travis.yml index 2abd7f82..7297721e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,7 +14,7 @@ matrix: - python: 3.8 dist: xenial sudo: required - - python: 3.9-dev + - python: 3.9 dist: xenial sudo: required env: From 0275bbe33d58675556d1eb15121350b41313f083 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 29 Oct 2020 14:14:34 +0100 Subject: [PATCH 181/378] fix 3.9 not used in appveyor jobs Signed-off-by: oleg.hoefling --- .appveyor.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.appveyor.yml b/.appveyor.yml index d945472a..c8beace3 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,7 +11,9 @@ environment: - python: 38 - python: 38-x64 - python: 39 + image: Visual Studio 2019 - python: 39-x64 + image: Visual Studio 2019 install: - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% From 5a21f3ff5700c51f3e746d01ff8fd757f8f5c37a Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 29 Oct 2020 16:31:07 +0100 Subject: [PATCH 182/378] install python 3.9 via windows installer on appveyor Signed-off-by: oleg.hoefling --- .appveyor.yml | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index c8beace3..a36ddda1 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -11,11 +11,31 @@ environment: - python: 38 - python: 38-x64 - python: 39 - image: Visual Studio 2019 + python_version: 3.9.0 - python: 39-x64 - image: Visual Studio 2019 + python_version: 3.9.0 install: + - ps: | + # from https://github.com/appveyor/build-images/blob/27bde614bc60d7ef7a8bc46182f4d7582fa11b56/scripts/Windows/install_python.ps1#L88-L108 + function InstallPythonEXE($targetPath, $version) { + $urlPlatform = "" + if ($targetPath -match '-x64$') { + $urlPlatform = "-amd64" + } + Write-Host "Installing Python $version$urlPlatform to $($targetPath)..." -ForegroundColor Cyan + $downloadUrl = "https://www.python.org/ftp/python/$version/python-$version$urlPlatform.exe" + Write-Host "Downloading $($downloadUrl)..." + $exePath = "$env:TEMP\python-$version.exe" + (New-Object Net.WebClient).DownloadFile($downloadUrl, $exePath) + Write-Host "Installing..." + cmd /c start /wait $exePath /quiet TargetDir="$targetPath" Shortcuts=0 Include_launcher=1 InstallLauncherAllUsers=1 Include_debug=1 + Remove-Item $exePath + Write-Host "Installed Python $version" -ForegroundColor Green + } + if ( -not ( Test-Path -Path C:\\Python$env:PYTHON -PathType Container ) ) { + InstallPythonEXE C:\\Python$env:PYTHON $env:PYTHON_VERSION + } - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% - python -m pip install -U pip wheel setuptools From b7e940872c318de4fb3a4520c67812e7585df1b9 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 30 Oct 2020 00:29:45 +0100 Subject: [PATCH 183/378] install from wheels in ci to run tests over real installation Signed-off-by: oleg.hoefling --- .github/workflows/macosx.yml | 2 +- .travis.yml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index c8bfee95..6851af3a 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -32,7 +32,7 @@ jobs: run: | rm -rf build/ pip install coverage --upgrade -r requirements-test.txt - pip install --editable . + pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ - name: Run tests run: | coverage run -m pytest -v --color=yes diff --git a/.travis.yml b/.travis.yml index 7297721e..4e403f90 100644 --- a/.travis.yml +++ b/.travis.yml @@ -36,8 +36,8 @@ addons: install: - travis_retry pip install --upgrade pip setuptools wheel - travis_retry pip install coverage -r requirements-test.txt --upgrade --force-reinstall -- travis_retry pip install -e "." -- pip list +- python setup.py bdist_wheel +- pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ script: coverage run -m pytest -v tests --color=yes after_success: - lcov --capture --no-external --directory . --output-file coverage.info From d5f461dae335292508eaef538509e23d4c97fc07 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 13 Nov 2020 22:08:02 +0100 Subject: [PATCH 184/378] don't build for python 2.7 Signed-off-by: oleg.hoefling --- .appveyor.yml | 2 -- .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux2010.yml | 2 +- .travis.yml | 1 - setup.py | 55 ++++++++--------------------- 5 files changed, 16 insertions(+), 46 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index a36ddda1..54bd2b1e 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -1,7 +1,5 @@ environment: matrix: - - python: 27 - - python: 27-x64 - python: 35 - python: 35-x64 - python: 36 diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 6851af3a..01302083 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [2.7, 3.5, 3.6, 3.7, 3.8, 3.9] + python: [3.5, 3.6, 3.7, 3.8, 3.9] steps: - uses: actions/checkout@v1 - name: Setup Python diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 637983d4..2190378b 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -6,7 +6,7 @@ jobs: container: quay.io/pypa/manylinux2010_x86_64 strategy: matrix: - python-abi: [cp27-cp27m, cp27-cp27mu, cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] + python-abi: [cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] steps: - uses: actions/checkout@v1 - name: Install build dependencies diff --git a/.travis.yml b/.travis.yml index 4e403f90..9106805a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,6 @@ notifications: email: false matrix: include: - - python: 2.7 - python: 3.5 - python: 3.6 - python: 3.7 diff --git a/setup.py b/setup.py index 976489c6..2838fe84 100644 --- a/setup.py +++ b/setup.py @@ -7,27 +7,18 @@ import zipfile from distutils import log from distutils.errors import DistutilsError +from pathlib import Path +from urllib.request import urlcleanup, urljoin, urlretrieve from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig -if sys.version_info >= (3, 4): - from urllib.request import urlcleanup, urljoin, urlretrieve -else: - from urllib import urlcleanup, urlretrieve - from urlparse import urljoin - class build_ext(build_ext_orig, object): def info(self, message): self.announce(message, level=log.INFO) def run(self): - if sys.version_info >= (3, 4): - from pathlib import Path - else: - from pathlib2 import Path - ext = self.ext_map['xmlsec'] self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) @@ -107,16 +98,10 @@ def run(self): def prepare_static_build_win(self): release_url = 'https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/' - if sys.version_info < (3, 5): - if sys.maxsize > 2147483647: - suffix = 'vs2008.win64' - else: - suffix = "vs2008.win32" + if sys.maxsize > 2147483647: + suffix = 'win64' else: - if sys.maxsize > 2147483647: - suffix = "win64" - else: - suffix = "win32" + suffix = 'win32' libs = [ 'libxml2-2.9.4.{}.zip'.format(suffix), @@ -185,7 +170,7 @@ def prepare_static_build_linux(self): self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', None) self.libxslt_version = os.environ.get('PYXMLSEC_LIBXLST_VERSION', None) self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.2.11') - self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.2.30') + self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.2.31') self.info('Settings:') self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) @@ -402,26 +387,11 @@ def prepare_static_build_linux(self): ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] -if sys.version_info >= (3, 4): - from pathlib import Path - - src_root = Path(__file__).parent / 'src' - sources = [str(p.absolute()) for p in src_root.rglob('*.c')] -else: - import fnmatch - - src_root = os.path.join(os.path.dirname(__file__), 'src') - sources = [] - for root, _, files in os.walk(src_root): - for file in fnmatch.filter(files, '*.c'): - sources.append(os.path.join(root, file)) - +src_root = Path(__file__).parent / 'src' +sources = [str(p.absolute()) for p in src_root.rglob('*.c')] pyxmlsec = Extension('xmlsec', sources=sources) setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] -if sys.version_info < (3, 4): - setup_reqs.append('pathlib2') - with io.open('README.rst', encoding='utf-8') as f: long_desc = f.read() @@ -434,7 +404,7 @@ def prepare_static_build_linux(self): long_description=long_desc, ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, - python_requires='>=2.7, !=3.0.*, !=3.1.*, !=3.2.*, !=3.3.*, !=3.4.*', + python_requires='>=3.5', setup_requires=setup_reqs, install_requires=['lxml>=3.8'], author="Bulat Gaifullin", @@ -442,7 +412,10 @@ def prepare_static_build_linux(self): maintainer='Oleg Hoefling', maintainer_email='oleg.hoefling@gmail.com', url='https://github.com/mehcode/python-xmlsec', - project_urls={'Documentation': 'https://xmlsec.readthedocs.io', 'Source': 'https://github.com/mehcode/python-xmlsec',}, + project_urls={ + 'Documentation': 'https://xmlsec.readthedocs.io', + 'Source': 'https://github.com/mehcode/python-xmlsec', + }, license='MIT', keywords=['xmlsec'], classifiers=[ @@ -452,12 +425,12 @@ def prepare_static_build_linux(self): 'License :: OSI Approved :: MIT License', 'Operating System :: OS Independent', 'Programming Language :: C', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.5', 'Programming Language :: Python :: 3.6', 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', + 'Programming Language :: Python :: 3.9', 'Topic :: Text Processing :: Markup :: XML', 'Typing :: Typed', ], From c147027772c61761c56c119f0b4296fade9a3380 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sun, 25 Apr 2021 20:10:07 +0200 Subject: [PATCH 185/378] drop set-env usage in gh actions Signed-off-by: oleg.hoefling --- .github/workflows/macosx.yml | 20 ++++++++++---------- .github/workflows/manylinux2010.yml | 8 ++++---- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 01302083..70e00291 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -17,28 +17,28 @@ jobs: pip install --upgrade pip setuptools wheel brew install libxml2 libxmlsec1 pkg-config - name: Build macosx_x86_64 wheel + env: + CC: clang + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" + LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" run: | python setup.py bdist_wheel + rm -rf build/ - name: Set environment variables shell: bash run: | - echo ::set-env name=PKGVER::$(python setup.py --version) - echo ::set-env name=LLVM_PROFILE_FILE::"pyxmlsec-%p.profraw" + echo "PKGVER=$(python setup.py --version)" >> $GITHUB_ENV + echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV - name: Install test dependencies - env: - CC: clang - CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" - LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" run: | - rm -rf build/ pip install coverage --upgrade -r requirements-test.txt pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV - name: Run tests run: | coverage run -m pytest -v --color=yes - name: Report coverage to codecov run: | - LIBFILE=$(python -c "import xmlsec; print(xmlsec.__file__)") - /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse pyxmlsec-*.profraw -output pyxmlsec.profdata - /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${LIBFILE} -instr-profile=pyxmlsec.profdata src > coverage.txt + /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata + /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} -instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 2190378b..046cb855 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -15,7 +15,7 @@ jobs: - name: Set environment variables shell: bash run: | - echo ::set-env name=PKGVER::$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version) + echo "PKGVER=$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version)" >> $GITHUB_ENV - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true @@ -24,10 +24,10 @@ jobs: - name: Label manylinux2010_x86_64 wheel run: | ls -la dist/ - auditwheel show dist/xmlsec-${PKGVER}-${{ matrix.python-abi }}-linux_x86_64.whl - auditwheel repair dist/xmlsec-${PKGVER}-${{ matrix.python-abi }}-linux_x86_64.whl + auditwheel show dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl + auditwheel repair dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl ls -l wheelhouse/ - auditwheel show wheelhouse/xmlsec-${PKGVER}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl + auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl - name: Install test dependencies run: | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt From ce45868701220368f156114978c784cc5200d80c Mon Sep 17 00:00:00 2001 From: Roman513 Date: Fri, 23 Apr 2021 23:45:17 +0300 Subject: [PATCH 186/378] Fix xmlsec version comparison macro Use 8 instead of 4 bits for all xmlsec version fields to prevent overflow starting from version number 1.2.32 --- src/constants.c | 9 ++++++--- src/main.c | 2 +- src/platform.h | 4 ++-- 3 files changed, 9 insertions(+), 6 deletions(-) diff --git a/src/constants.c b/src/constants.c index 68f086e9..b4cdedf4 100644 --- a/src/constants.c +++ b/src/constants.c @@ -452,7 +452,8 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDsa, "DSA") #endif -#if XMLSEC_VERSION_HEX > 306 +#if XMLSEC_VERSION_HEX > 0x10212 + // from version 1.2.19 PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEcdsa, "ECDSA") #endif PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataHmac, "HMAC") @@ -502,7 +503,8 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDsaSha1, "DSA_SHA1"); #endif -#if XMLSEC_VERSION_HEX > 306 +#if XMLSEC_VERSION_HEX > 0x10212 + // from version 1.2.19 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha1, "ECDSA_SHA1"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha224, "ECDSA_SHA224"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha256, "ECDSA_SHA256"); @@ -543,7 +545,8 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha384, "SHA384"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformSha512, "SHA512"); -#if XMLSEC_VERSION_HEX > 315 +#if XMLSEC_VERSION_HEX > 0x1021B + // from version 1.2.28 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes128Gcm, "AES128_GCM"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes192Gcm, "AES192_GCM"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformAes256Gcm, "AES256_GCM"); diff --git a/src/main.c b/src/main.c index 59989529..c097d7f5 100644 --- a/src/main.c +++ b/src/main.c @@ -27,7 +27,7 @@ static int free_mode = _PYXMLSEC_FREE_NONE; #ifndef XMLSEC_NO_CRYPTO_DYNAMIC_LOADING static const xmlChar* PyXmlSec_GetCryptoLibName() { -#if XMLSEC_VERSION_HEX > 308 +#if XMLSEC_VERSION_HEX > 0x10214 // xmlSecGetDefaultCrypto was introduced in version 1.2.21 const xmlChar* cryptoLib = xmlSecGetDefaultCrypto(); #else diff --git a/src/platform.h b/src/platform.h index 795062f2..01312a11 100644 --- a/src/platform.h +++ b/src/platform.h @@ -19,11 +19,11 @@ #include #endif /* MS_WIN32 */ -#define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 8) | (XMLSEC_VERSION_MINOR << 4) | (XMLSEC_VERSION_SUBMINOR)) +#define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 16) | (XMLSEC_VERSION_MINOR << 8) | (XMLSEC_VERSION_SUBMINOR)) // XKMS support was removed in version 1.2.21 // https://mail.gnome.org/archives/commits-list/2015-February/msg10555.html -#if XMLSEC_VERSION_HEX > 0x134 +#if XMLSEC_VERSION_HEX > 0x10214 #define XMLSEC_NO_XKMS 1 #endif From 7e76c45f152a8ef7a6e4b4937196a0ee9c2ed748 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 26 May 2021 13:03:57 +0200 Subject: [PATCH 187/378] add XMLSEC_NO_XSLT check Signed-off-by: oleg.hoefling --- src/constants.c | 4 +++- tests/test_ds.py | 2 ++ tests/test_templates.py | 2 ++ 3 files changed, 7 insertions(+), 1 deletion(-) diff --git a/src/constants.c b/src/constants.c index b4cdedf4..93c6e434 100644 --- a/src/constants.c +++ b/src/constants.c @@ -485,7 +485,6 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPath, "XPATH"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPath2, "XPATH2"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXPointer, "XPOINTER"); - PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXslt, "XSLT"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRemoveXmlTagsC14N, "REMOVE_XML_TAGS_C14N"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformVisa3DHack, "VISA3D_HACK"); @@ -502,6 +501,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDsaSha1, "DSA_SHA1"); #endif +#ifndef XMLSEC_NO_XSLT + PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformXslt, "XSLT"); +#endif #if XMLSEC_VERSION_HEX > 0x10212 // from version 1.2.19 diff --git a/tests/test_ds.py b/tests/test_ds.py index cf49ee71..98b6424b 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -1,3 +1,4 @@ +import unittest import xmlsec from tests import base @@ -194,6 +195,7 @@ def test_sign_binary_no_key(self): with self.assertRaisesRegex(xmlsec.Error, 'Sign key is not specified.'): ctx.sign_binary(bytes=b'', transform=consts.TransformRsaSha1) + @unittest.skipIf(not hasattr(consts, 'TransformXslt'), reason='XSLT transformations not enabled') def test_sign_binary_invalid_signature_method(self): ctx = xmlsec.SignatureContext() ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) diff --git a/tests/test_templates.py b/tests/test_templates.py index 947e0bbc..9475c5e4 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -1,3 +1,4 @@ +import unittest from lxml import etree import xmlsec @@ -195,6 +196,7 @@ def test_encrypted_data_ensure_key_info_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.encrypted_data_ensure_key_info('') + @unittest.skipIf(not hasattr(consts, 'TransformXslt'), reason='XSLT transformations not enabled') def test_transform_add_c14n_inclusive_namespaces(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) From 609fac746c34dfcf34cf3c5e9d3f4ddf2c8c8dde Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 26 May 2021 13:13:39 +0200 Subject: [PATCH 188/378] drop manylinux wheel build for python 3.5 Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 046cb855..68211946 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -6,7 +6,7 @@ jobs: container: quay.io/pypa/manylinux2010_x86_64 strategy: matrix: - python-abi: [cp35-cp35m, cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] + python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] steps: - uses: actions/checkout@v1 - name: Install build dependencies From db81f9e32eced602d640965ae6f17ac87e6f63e0 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 26 May 2021 14:22:33 +0200 Subject: [PATCH 189/378] prohibit static builds with libxml2-2.9.12, see https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 ++ .github/workflows/sdist.yml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 68211946..52e02ba2 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -19,6 +19,8 @@ jobs: - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true + # disable libxml2-2.9.12 because of https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 + PYXMLSEC_LIBXML2_VERSION: 2.9.10 run: | /opt/python/${{ matrix.python-abi }}/bin/python setup.py bdist_wheel - name: Label manylinux2010_x86_64 wheel diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 5b5dac96..d6cf6c9d 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -18,6 +18,8 @@ jobs: - name: Install test dependencies env: PYXMLSEC_STATIC_DEPS: true + # disable libxml2-2.9.12 because of https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 + PYXMLSEC_LIBXML2_VERSION: 2.9.10 run: | pip install --upgrade -r requirements-test.txt pip install dist/xmlsec-$(python setup.py --version).tar.gz From cd7ca859921e1ae66c6bf9fb3f6bc3b78f2146af Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 26 May 2021 14:28:24 +0200 Subject: [PATCH 190/378] adjust to PEP 600 changes Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 52e02ba2..e2b1f449 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -29,7 +29,7 @@ jobs: auditwheel show dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl auditwheel repair dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl ls -l wheelhouse/ - auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-manylinux2010_x86_64.whl + auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-manylinux_2_12_x86_64.manylinux2010_x86_64.whl - name: Install test dependencies run: | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt From 95ed6fd12cc13d563d79f34bbe339e2d21fe88f8 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Wed, 26 May 2021 14:58:53 +0200 Subject: [PATCH 191/378] add linuxbrew build Signed-off-by: oleg.hoefling --- .github/workflows/linuxbrew.yml | 33 +++++++++++++++++++++++++++++++++ README.rst | 2 ++ 2 files changed, 35 insertions(+) create mode 100644 .github/workflows/linuxbrew.yml diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml new file mode 100644 index 00000000..6502b830 --- /dev/null +++ b/.github/workflows/linuxbrew.yml @@ -0,0 +1,33 @@ +name: linuxbrew +on: [push, pull_request] +jobs: + linuxbrew: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v1 + - name: Setup Python + uses: actions/setup-python@v2 + with: + python-version: ${{ matrix.python }} + - name: Install build dependencies + run: | + sudo apt install -y build-essential procps curl file git + /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" + test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv) + test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile + echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile + brew update + brew install python gcc libxml2 libxmlsec1 pkg-config + pip3 install --upgrade setuptools wheel + ln -s $(brew --prefix)/bin/gcc-11 $(brew --prefix)/bin/gcc-5 + - name: Build linux_x86_64 wheel + run: | + python3 setup.py bdist_wheel + rm -rf build/ + - name: Install test dependencies + run: | + pip3 install --upgrade -r requirements-test.txt + pip3 install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + - name: Run tests + run: | + pytest -v --color=yes diff --git a/README.rst b/README.rst index f01d467d..22235af4 100644 --- a/README.rst +++ b/README.rst @@ -11,6 +11,8 @@ python-xmlsec :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 .. image:: https://github.com/mehcode/python-xmlsec/workflows/MacOS/badge.svg :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22MacOS%22 +.. image:: https://github.com/mehcode/python-xmlsec/workflows/linuxbrew/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22linuxbrew%22 .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs From 6a1374d2a09d5e969c3379a95c2a234c4faff7b5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:14:46 +0200 Subject: [PATCH 192/378] replace PyString_FromString usages with PyUnicode_FromString Signed-off-by: oleg.hoefling --- src/constants.c | 22 +++++++++++----------- src/keys.c | 2 +- src/platform.h | 2 -- src/template.c | 2 +- src/utils.c | 2 +- 5 files changed, 14 insertions(+), 16 deletions(-) diff --git a/src/constants.c b/src/constants.c index 93c6e434..66aa88c7 100644 --- a/src/constants.c +++ b/src/constants.c @@ -27,7 +27,7 @@ static PyObject* PyXmlSec_Transform__str__(PyObject* self) { else snprintf(buf, sizeof(buf), "%s, None", transform->id->name); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } // __repr__ method @@ -38,18 +38,18 @@ static PyObject* PyXmlSec_Transform__repr__(PyObject* self) { snprintf(buf, sizeof(buf), "__Transform('%s', '%s', %d)", transform->id->name, transform->id->href, transform->id->usage); else snprintf(buf, sizeof(buf), "__Transform('%s', None, %d)", transform->id->name, transform->id->usage); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } static const char PyXmlSec_TransformNameGet__doc__[] = "The transform's name."; static PyObject* PyXmlSec_TransformNameGet(PyXmlSec_Transform* self, void* closure) { - return PyString_FromString((const char*)self->id->name); + return PyUnicode_FromString((const char*)self->id->name); } static const char PyXmlSec_TransformHrefGet__doc__[] = "The transform's identification string (href)."; static PyObject* PyXmlSec_TransformHrefGet(PyXmlSec_Transform* self, void* closure) { if (self->id->href != NULL) - return PyString_FromString((const char*)self->id->href); + return PyUnicode_FromString((const char*)self->id->href); Py_RETURN_NONE; } @@ -149,7 +149,7 @@ static PyObject* PyXmlSec_KeyData__str__(PyObject* self) { snprintf(buf, sizeof(buf), "%s, %s", keydata->id->name, keydata->id->href); else snprintf(buf, sizeof(buf), "%s, None", keydata->id->name); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } // __repr__ method @@ -160,18 +160,18 @@ static PyObject* PyXmlSec_KeyData__repr__(PyObject* self) { snprintf(buf, sizeof(buf), "__KeyData('%s', '%s')", keydata->id->name, keydata->id->href); else snprintf(buf, sizeof(buf), "__KeyData('%s', None)", keydata->id->name); - return PyString_FromString(buf); + return PyUnicode_FromString(buf); } static const char PyXmlSec_KeyDataNameGet__doc__[] = "The key data's name."; static PyObject* PyXmlSec_KeyDataNameGet(PyXmlSec_KeyData* self, void* closure) { - return PyString_FromString((const char*)self->id->name); + return PyUnicode_FromString((const char*)self->id->name); } static const char PyXmlSec_KeyDataHrefGet__doc__[] = "The key data's identification string (href)."; static PyObject* PyXmlSec_KeyDataHrefGet(PyXmlSec_KeyData* self, void* closure) { if (self->id->href != NULL) - return PyString_FromString((const char*)self->id->href); + return PyUnicode_FromString((const char*)self->id->href); Py_RETURN_NONE; } @@ -308,7 +308,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #define PYXMLSEC_ADD_NS_CONSTANT(name, lname) \ - tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + tmp = PyUnicode_FromString((const char*)(JOIN(xmlSec, name))); \ PYXMLSEC_ADD_CONSTANT(nsCls, name, lname); // namespaces @@ -334,7 +334,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #define PYXMLSEC_ADD_ENC_CONSTANT(name, lname) \ - tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + tmp = PyUnicode_FromString((const char*)(JOIN(xmlSec, name))); \ PYXMLSEC_ADD_CONSTANT(encryptionTypeCls, name, lname); // encryption type @@ -349,7 +349,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #define PYXMLSEC_ADD_NODE_CONSTANT(name, lname) \ - tmp = PyString_FromString((const char*)(JOIN(xmlSec, name))); \ + tmp = PyUnicode_FromString((const char*)(JOIN(xmlSec, name))); \ PYXMLSEC_ADD_CONSTANT(nodeCls, name, lname); // node diff --git a/src/keys.c b/src/keys.c index 357cc9c7..83419623 100644 --- a/src/keys.c +++ b/src/keys.c @@ -436,7 +436,7 @@ static PyObject* PyXmlSec_KeyNameGet(PyObject* self, void* closure) { } cname = (const char*)xmlSecKeyGetName(key->handle); if (cname != NULL) { - return PyString_FromString(cname); + return PyUnicode_FromString(cname); } Py_RETURN_NONE; } diff --git a/src/platform.h b/src/platform.h index 01312a11..a45b8b82 100644 --- a/src/platform.h +++ b/src/platform.h @@ -40,8 +40,6 @@ typedef int Py_ssize_t; #define PyString_Check PyUnicode_Check #define PyString_FromStringAndSize PyUnicode_FromStringAndSize -#define PyString_FromString PyUnicode_FromString - #define PyString_AsString PyUnicode_AsUTF8 #define PyString_AsUtf8AndSize PyUnicode_AsUTF8AndSize diff --git a/src/template.c b/src/template.c index 7d043606..9d19aaf3 100644 --- a/src/template.c +++ b/src/template.c @@ -766,7 +766,7 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, goto ON_FAIL; } if (PyList_Check(prefixes) || PyTuple_Check(prefixes)) { - sep = PyString_FromString(" "); + sep = PyUnicode_FromString(" "); prefixes = PyObject_CallMethod(sep, "join", "O", prefixes); Py_DECREF(sep); } else if (PyString_Check(prefixes)) { diff --git a/src/utils.c b/src/utils.c index ea6867f3..5f716128 100644 --- a/src/utils.c +++ b/src/utils.c @@ -32,7 +32,7 @@ PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { } int PyXmlSec_SetStringAttr(PyObject* obj, const char* name, const char* value) { - PyObject* tmp = PyString_FromString(value); + PyObject* tmp = PyUnicode_FromString(value); int r; if (tmp == NULL) { From 908edee62f02a30ea9a780caa980d01a8f837642 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:16:21 +0200 Subject: [PATCH 193/378] replace PyString_Check usages with PyUnicode_Check Signed-off-by: oleg.hoefling --- src/platform.h | 2 -- src/template.c | 2 +- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/src/platform.h b/src/platform.h index a45b8b82..dea74417 100644 --- a/src/platform.h +++ b/src/platform.h @@ -37,7 +37,6 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 -#define PyString_Check PyUnicode_Check #define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_AsString PyUnicode_AsUTF8 @@ -48,7 +47,6 @@ typedef int Py_ssize_t; #define PyString_FSConverter PyUnicode_FSConverter #else // PY3K -#define PyBytes_Check PyString_Check #define PyBytes_FromStringAndSize PyString_FromStringAndSize #define PyBytes_AsString PyString_AsString diff --git a/src/template.c b/src/template.c index 9d19aaf3..2fb87369 100644 --- a/src/template.c +++ b/src/template.c @@ -769,7 +769,7 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, sep = PyUnicode_FromString(" "); prefixes = PyObject_CallMethod(sep, "join", "O", prefixes); Py_DECREF(sep); - } else if (PyString_Check(prefixes)) { + } else if (PyUnicode_Check(prefixes)) { Py_INCREF(prefixes); } else { PyErr_SetString(PyExc_TypeError, "expected instance of str or list of str"); From 8977ff3232b54d56b25404e7f5ebd83cf6caf6ed Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:19:00 +0200 Subject: [PATCH 194/378] drop unused PyString_FromStringAndSize and PyString_AsUtf8AndSize Signed-off-by: oleg.hoefling --- src/platform.h | 9 --------- 1 file changed, 9 deletions(-) diff --git a/src/platform.h b/src/platform.h index dea74417..0062a930 100644 --- a/src/platform.h +++ b/src/platform.h @@ -37,26 +37,17 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 -#define PyString_FromStringAndSize PyUnicode_FromStringAndSize #define PyString_AsString PyUnicode_AsUTF8 -#define PyString_AsUtf8AndSize PyUnicode_AsUTF8AndSize #define PyCreateDummyObject PyModule_New #define PyString_FSConverter PyUnicode_FSConverter #else // PY3K -#define PyBytes_FromStringAndSize PyString_FromStringAndSize - #define PyBytes_AsString PyString_AsString #define PyBytes_AsStringAndSize PyString_AsStringAndSize -static inline char* PyString_AsUtf8AndSize(PyObject *obj, Py_ssize_t* length) { - char* buffer = NULL; - return (PyString_AsStringAndSize(obj, &buffer, length) < 0) ? (char*)(0) : buffer; -} - static inline PyObject* PyCreateDummyObject(const char* name) { PyObject* tmp = Py_InitModule(name, NULL); Py_INCREF(tmp); From c1e269abdc36cf391ebdea45042fbf654e5fe92e Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:21:03 +0200 Subject: [PATCH 195/378] replace PyString_AsString usages with PyUnicode_AsUTF8 Signed-off-by: oleg.hoefling --- src/keys.c | 2 +- src/platform.h | 3 --- src/template.c | 2 +- src/tree.c | 2 +- 4 files changed, 3 insertions(+), 6 deletions(-) diff --git a/src/keys.c b/src/keys.c index 83419623..9e65be8f 100644 --- a/src/keys.c +++ b/src/keys.c @@ -460,7 +460,7 @@ static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { return 0; } - name = PyString_AsString(value); + name = PyUnicode_AsUTF8(value); if (name == NULL) return -1; if (xmlSecKeySetName(key->handle, XSTR(name)) < 0) { diff --git a/src/platform.h b/src/platform.h index 0062a930..fe1c6f9b 100644 --- a/src/platform.h +++ b/src/platform.h @@ -38,14 +38,11 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 -#define PyString_AsString PyUnicode_AsUTF8 - #define PyCreateDummyObject PyModule_New #define PyString_FSConverter PyUnicode_FSConverter #else // PY3K -#define PyBytes_AsString PyString_AsString #define PyBytes_AsStringAndSize PyString_AsStringAndSize static inline PyObject* PyCreateDummyObject(const char* name) { diff --git a/src/template.c b/src/template.c index 2fb87369..0d35832b 100644 --- a/src/template.c +++ b/src/template.c @@ -781,7 +781,7 @@ static PyObject* PyXmlSec_TemplateTransformAddC14NInclNamespaces(PyObject* self, } - c_prefixes = PyString_AsString(prefixes); + c_prefixes = PyUnicode_AsUTF8(prefixes); Py_BEGIN_ALLOW_THREADS; res = xmlSecTmplTransformAddC14NInclNamespaces(node->_c_node, XSTR(c_prefixes)); Py_END_ALLOW_THREADS; diff --git a/src/tree.c b/src/tree.c index 76037d3b..df8821c3 100644 --- a/src/tree.c +++ b/src/tree.c @@ -182,7 +182,7 @@ static PyObject* PyXmlSec_TreeAddIds(PyObject* self, PyObject *args, PyObject *k tmp = PyObject_GetItem(ids, key); Py_DECREF(key); if (tmp == NULL) goto ON_FAIL; - list[i] = XSTR(PyString_AsString(tmp)); + list[i] = XSTR(PyUnicode_AsUTF8(tmp)); Py_DECREF(tmp); if (list[i] == NULL) goto ON_FAIL; } From d29be044a03aec424ecc0602a0ab8d79c7311d94 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:22:35 +0200 Subject: [PATCH 196/378] replace PyCreateDummyObject usages with PyModule_New Signed-off-by: oleg.hoefling --- src/constants.c | 2 +- src/platform.h | 8 -------- 2 files changed, 1 insertion(+), 9 deletions(-) diff --git a/src/constants.c b/src/constants.c index 66aa88c7..938d5834 100644 --- a/src/constants.c +++ b/src/constants.c @@ -292,7 +292,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #undef PYXMLSEC_ADD_INT_CONSTANT #define PYXMLSEC_DECLARE_NAMESPACE(var, name) \ - if (!(var = PyCreateDummyObject(name))) goto ON_FAIL; \ + if (!(var = PyModule_New(name))) goto ON_FAIL; \ if (PyModule_AddObject(package, name, var) < 0) goto ON_FAIL; \ Py_INCREF(var); // add object steels reference diff --git a/src/platform.h b/src/platform.h index fe1c6f9b..25c24d19 100644 --- a/src/platform.h +++ b/src/platform.h @@ -38,19 +38,11 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 -#define PyCreateDummyObject PyModule_New - #define PyString_FSConverter PyUnicode_FSConverter #else // PY3K #define PyBytes_AsStringAndSize PyString_AsStringAndSize -static inline PyObject* PyCreateDummyObject(const char* name) { - PyObject* tmp = Py_InitModule(name, NULL); - Py_INCREF(tmp); - return tmp; -} - static inline int PyString_FSConverter(PyObject* o, PyObject** p) { if (o == NULL) { return 0; From cfe61ea2c4040a5ce11d003ef894412eddc7be89 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:26:07 +0200 Subject: [PATCH 197/378] replace PyString_FSConverter usages with PyUnicode_FSConverter Signed-off-by: oleg.hoefling --- src/keys.c | 4 ++-- src/platform.h | 12 ------------ src/utils.c | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/keys.c b/src/keys.c index 9e65be8f..8e065ea0 100644 --- a/src/keys.c +++ b/src/keys.c @@ -249,7 +249,7 @@ static PyObject* PyXmlSec_KeyFromBinaryFile(PyObject* self, PyObject* args, PyOb PYXMLSEC_DEBUG("load symmetric key - start"); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O!O&:from_binary_file", kwlist, - PyXmlSec_KeyDataType, &keydata, PyString_FSConverter, &filepath)) + PyXmlSec_KeyDataType, &keydata, PyUnicode_FSConverter, &filepath)) { goto ON_FAIL; } @@ -698,7 +698,7 @@ static PyObject* PyXmlSec_KeysManagerLoadCert(PyObject* self, PyObject* args, Py PYXMLSEC_DEBUGF("%p: load cert - start", self); if (!PyArg_ParseTupleAndKeywords(args, kwargs, "O&II:load_cert", kwlist, - PyString_FSConverter, &filepath, &format, &type)) { + PyUnicode_FSConverter, &filepath, &format, &type)) { goto ON_FAIL; } diff --git a/src/platform.h b/src/platform.h index 25c24d19..35705f2d 100644 --- a/src/platform.h +++ b/src/platform.h @@ -37,22 +37,10 @@ typedef int Py_ssize_t; #if PY_MAJOR_VERSION >= 3 #define PY3K 1 - -#define PyString_FSConverter PyUnicode_FSConverter #else // PY3K #define PyBytes_AsStringAndSize PyString_AsStringAndSize -static inline int PyString_FSConverter(PyObject* o, PyObject** p) { - if (o == NULL) { - return 0; - } - - Py_INCREF(o); - *p = o; - return 1; -} - #endif // PYTHON3 static inline char* PyBytes_AsStringAndSize2(PyObject *obj, Py_ssize_t* length) { diff --git a/src/utils.c b/src/utils.c index 5f716128..cdcb182b 100644 --- a/src/utils.c +++ b/src/utils.c @@ -25,7 +25,7 @@ PyObject* PyXmlSec_GetFilePathOrContent(PyObject* file, int* is_content) { return data; } *is_content = 0; - if (!PyString_FSConverter(file, &tmp)) { + if (!PyUnicode_FSConverter(file, &tmp)) { return NULL; } return tmp; From 5055be674a2de83094900591935a096173d74e1d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 17:48:11 +0200 Subject: [PATCH 198/378] remove python 2 code bits Signed-off-by: oleg.hoefling --- src/constants.c | 7 ------- src/main.c | 51 ------------------------------------------------- src/platform.h | 8 -------- src/template.c | 7 ------- src/tree.c | 7 ------- 5 files changed, 80 deletions(-) diff --git a/src/constants.c b/src/constants.c index 938d5834..8c17e389 100644 --- a/src/constants.c +++ b/src/constants.c @@ -245,7 +245,6 @@ static PyObject* PyXmlSec_KeyDataNew(xmlSecKeyDataId id) { return (PyObject*)keydata; } -#ifdef PY3K static PyModuleDef PyXmlSec_ConstantsModule = { PyModuleDef_HEAD_INIT, @@ -253,7 +252,6 @@ static PyModuleDef PyXmlSec_ConstantsModule = PYXMLSEC_CONSTANTS_DOC, -1, NULL, NULL, NULL, NULL, NULL }; -#endif // PY3K // initialize constants module and registers it base package int PyXmlSec_ConstantsModule_Init(PyObject* package) { @@ -267,12 +265,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PyObject* keyDataTypeCls = NULL; PyObject* tmp = NULL; -#ifdef PY3K constants = PyModule_Create(&PyXmlSec_ConstantsModule); -#else - constants = Py_InitModule3(STRINGIFY(MODULE_NAME) ".constants", NULL, PYXMLSEC_CONSTANTS_DOC); - Py_XINCREF(constants); -#endif if (!constants) return -1; diff --git a/src/main.c b/src/main.c index c097d7f5..a602982c 100644 --- a/src/main.c +++ b/src/main.c @@ -203,8 +203,6 @@ int PyXmlSec_EncModule_Init(PyObject* package); // templates management int PyXmlSec_TemplateModule_Init(PyObject* package); -#ifdef PY3K - static int PyXmlSec_PyClear(PyObject *self) { PyXmlSec_Free(free_mode); return 0; @@ -225,54 +223,12 @@ static PyModuleDef PyXmlSecModule = { #define PYENTRY_FUNC_NAME JOIN(PyInit_, MODULE_NAME) #define PY_MOD_RETURN(m) return m -#else // PY3K -#define PYENTRY_FUNC_NAME JOIN(init, MODULE_NAME) -#define PY_MOD_RETURN(m) return - -static void PyXmlSec_PyModuleGuard__del__(PyObject* self) -{ - PyXmlSec_Free(free_mode); - Py_TYPE(self)->tp_free(self); -} - -// we need guard to free resources on module unload -typedef struct { - PyObject_HEAD -} PyXmlSec_PyModuleGuard; - -static PyTypeObject PyXmlSec_PyModuleGuardType = { - PyVarObject_HEAD_INIT(NULL, 0) - STRINGIFY(MODULE_NAME) "__Guard", /* tp_name */ - sizeof(PyXmlSec_PyModuleGuard), /* tp_basicsize */ - 0, /* tp_itemsize */ - PyXmlSec_PyModuleGuard__del__, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_reserved */ - 0, /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ -}; -#endif // PY3K PyMODINIT_FUNC PYENTRY_FUNC_NAME(void) { PyObject *module = NULL; -#ifdef PY3K module = PyModule_Create(&PyXmlSecModule); -#else - module = Py_InitModule3(STRINGIFY(MODULE_NAME), PyXmlSec_MainMethods, MODULE_DOC); -#endif if (!module) { PY_MOD_RETURN(NULL); /* this really should never happen */ } @@ -294,13 +250,6 @@ PYENTRY_FUNC_NAME(void) if (PyXmlSec_EncModule_Init(module) < 0) goto ON_FAIL; if (PyXmlSec_TemplateModule_Init(module) < 0) goto ON_FAIL; -#ifndef PY3K - if (PyType_Ready(&PyXmlSec_PyModuleGuardType) < 0) goto ON_FAIL; - PYXMLSEC_DEBUGF("%p", &PyXmlSec_PyModuleGuardType); - // added guard to free resources on module unload, this should be called after last - if (PyModule_AddObject(module, "__guard", _PyObject_New(&PyXmlSec_PyModuleGuardType)) < 0) goto ON_FAIL; -#endif - PY_MOD_RETURN(module); ON_FAIL: PY_MOD_RETURN(NULL); diff --git a/src/platform.h b/src/platform.h index 35705f2d..35163e88 100644 --- a/src/platform.h +++ b/src/platform.h @@ -35,14 +35,6 @@ typedef int Py_ssize_t; #define PY_SSIZE_T_MIN INT_MIN #endif -#if PY_MAJOR_VERSION >= 3 -#define PY3K 1 -#else // PY3K - -#define PyBytes_AsStringAndSize PyString_AsStringAndSize - -#endif // PYTHON3 - static inline char* PyBytes_AsStringAndSize2(PyObject *obj, Py_ssize_t* length) { char* buffer = NULL; return ((PyBytes_AsStringAndSize(obj, &buffer, length) < 0) ? (char*)(0) : buffer); diff --git a/src/template.c b/src/template.c index 0d35832b..ae0eca34 100644 --- a/src/template.c +++ b/src/template.c @@ -918,7 +918,6 @@ static PyMethodDef PyXmlSec_TemplateMethods[] = { {NULL, NULL} /* sentinel */ }; -#ifdef PY3K static PyModuleDef PyXmlSec_TemplateModule = { PyModuleDef_HEAD_INIT, @@ -931,15 +930,9 @@ static PyModuleDef PyXmlSec_TemplateModule = NULL, /* m_clear */ NULL, /* m_free */ }; -#endif // PY3K int PyXmlSec_TemplateModule_Init(PyObject* package) { -#ifdef PY3K PyObject* template = PyModule_Create(&PyXmlSec_TemplateModule); -#else - PyObject* template = Py_InitModule3(STRINGIFY(MODULE_NAME) ".template", PyXmlSec_TemplateMethods, PYXMLSEC_TEMPLATES_DOC); - Py_XINCREF(template); -#endif if (!template) goto ON_FAIL; PYXMLSEC_DEBUGF("%p", template); diff --git a/src/tree.c b/src/tree.c index df8821c3..37cae785 100644 --- a/src/tree.c +++ b/src/tree.c @@ -230,7 +230,6 @@ static PyMethodDef PyXmlSec_TreeMethods[] = { {NULL, NULL} /* sentinel */ }; -#ifdef PY3K static PyModuleDef PyXmlSec_TreeModule = { PyModuleDef_HEAD_INIT, @@ -243,16 +242,10 @@ static PyModuleDef PyXmlSec_TreeModule = NULL, /* m_clear */ NULL, /* m_free */ }; -#endif // PY3K int PyXmlSec_TreeModule_Init(PyObject* package) { -#ifdef PY3K PyObject* tree = PyModule_Create(&PyXmlSec_TreeModule); -#else - PyObject* tree = Py_InitModule3(STRINGIFY(MODULE_NAME) ".tree", PyXmlSec_TreeMethods, PYXMLSEC_TREE_DOC); - Py_XINCREF(tree); -#endif if (!tree) goto ON_FAIL; From 268c5881007c400227283647aa7b90c99a28f6e4 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 22:00:58 +0200 Subject: [PATCH 199/378] work around xmlsec overwriting custom callback on init Signed-off-by: oleg.hoefling --- pyproject.toml | 9 +-------- src/exception.c | 10 +++++++--- src/exception.h | 2 ++ src/main.c | 5 +++++ tests/base.py | 12 ++++++------ tests/test_constants.py | 3 ++- tests/test_ds.py | 5 +++-- tests/test_enc.py | 2 +- tests/test_keys.py | 22 +++++++++++----------- tests/test_templates.py | 5 +++-- tests/test_xmlsec.py | 4 ++-- 11 files changed, 43 insertions(+), 36 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 636c52c9..6c69db80 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -18,14 +18,7 @@ exclude = ''' ''' [tool.isort] -force_alphabetical_sort_within_sections = true -recursive = true -line_length = 130 -multi_line_output = 3 -include_trailing_comma = true -force_grid_wrap = 0 -use_parentheses = true -combine_as_imports = true +profile = 'black' known_first_party = ['xmlsec'] known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] diff --git a/src/exception.c b/src/exception.c index 2ca5ab57..176cf385 100644 --- a/src/exception.c +++ b/src/exception.c @@ -165,6 +165,12 @@ void PyXmlSecEnableDebugTrace(int v) { PyXmlSec_PrintErrorMessage = v; } +void PyXmlSec_InstallErrorCallback() { + if (PyXmlSec_LastErrorKey != 0) { + xmlSecErrorsSetCallback(PyXmlSec_ErrorCallback); + } +} + // initializes errors module int PyXmlSec_ExceptionsModule_Init(PyObject* package) { PyXmlSec_Error = NULL; @@ -185,9 +191,7 @@ int PyXmlSec_ExceptionsModule_Init(PyObject* package) { if (PyModule_AddObject(package, "VerificationError", PyXmlSec_VerificationError) < 0) goto ON_FAIL; PyXmlSec_LastErrorKey = PyThread_create_key(); - if (PyXmlSec_LastErrorKey != 0) { - xmlSecErrorsSetCallback(&PyXmlSec_ErrorCallback); - } + PyXmlSec_InstallErrorCallback(); return 0; diff --git a/src/exception.h b/src/exception.h index 9dea5ecb..687cd778 100644 --- a/src/exception.h +++ b/src/exception.h @@ -24,4 +24,6 @@ void PyXmlSec_ClearError(void); void PyXmlSecEnableDebugTrace(int); +void PyXmlSec_InstallErrorCallback(); + #endif //__PYXMLSEC_EXCEPTIONS_H__ diff --git a/src/main.c b/src/main.c index a602982c..c93b16d2 100644 --- a/src/main.c +++ b/src/main.c @@ -239,6 +239,11 @@ PYENTRY_FUNC_NAME(void) if (PyXmlSec_Init() < 0) goto ON_FAIL; + // xmlsec will install default callback in PyXmlSec_Init, + // overwriting any custom callbacks. + // We thus install our callback again now. + PyXmlSec_InstallErrorCallback(); + if (PyModule_AddStringConstant(module, "__version__", STRINGIFY(MODULE_VERSION)) < 0) goto ON_FAIL; if (PyXmlSec_InitLxmlModule() < 0) goto ON_FAIL; diff --git a/tests/base.py b/tests/base.py index cf659b61..e834f080 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,13 +1,13 @@ import gc import os import sys +import unittest from lxml import etree -import xmlsec -import unittest +import xmlsec -if sys.version_info < (3, ): +if sys.version_info < (3,): unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp @@ -21,6 +21,8 @@ def get_memory_usage(): return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss + + except ImportError: resource = None @@ -112,9 +114,7 @@ def assertXmlEqual(self, first, second, msg=None): self.fail('Tags do not match: %s and %s. %s' % (first.tag, second.tag, msg)) for name, value in first.attrib.items(): if second.attrib.get(name) != value: - self.fail( - 'Attributes do not match: %s=%r, %s=%r. %s' % (name, value, name, second.attrib.get(name), msg) - ) + self.fail('Attributes do not match: %s=%r, %s=%r. %s' % (name, value, name, second.attrib.get(name), msg)) for name in second.attrib.keys(): if name not in first.attrib: self.fail('x2 has an attribute x1 is missing: %s. %s' % (name, msg)) diff --git a/tests/test_constants.py b/tests/test_constants.py index 857a1cdd..689edce6 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -1,8 +1,9 @@ """Test constants from :mod:`xmlsec.constants` module.""" -import xmlsec from hypothesis import given, strategies +import xmlsec + def _constants(typename): return list( diff --git a/tests/test_ds.py b/tests/test_ds.py index 98b6424b..9417fedb 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -1,4 +1,5 @@ import unittest + import xmlsec from tests import base @@ -70,7 +71,7 @@ def test_sign_bad_args(self): def test_sign_fail(self): ctx = xmlsec.SignatureContext() ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) - with self.assertRaisesRegex(xmlsec.InternalError, 'failed to sign'): + with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'): ctx.sign(self.load_xml('sign1-in.xml')) def test_sign_case1(self): @@ -229,7 +230,7 @@ def test_verify_bad_args(self): def test_verify_fail(self): ctx = xmlsec.SignatureContext() ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) - with self.assertRaisesRegex(xmlsec.InternalError, 'failed to verify'): + with self.assertRaisesRegex(xmlsec.Error, 'failed to verify'): ctx.verify(self.load_xml('sign1-in.xml')) def test_verify_case_1(self): diff --git a/tests/test_enc.py b/tests/test_enc.py index 141e5753..7add848c 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -191,7 +191,7 @@ def test_encrypt_uri_bad_args(self): def test_encrypt_uri_fail(self): ctx = xmlsec.EncryptionContext() - with self.assertRaisesRegex(xmlsec.InternalError, 'failed to encrypt URI'): + with self.assertRaisesRegex(xmlsec.Error, 'failed to encrypt URI'): ctx.encrypt_uri(etree.Element('root'), '') def test_decrypt1(self): diff --git a/tests/test_keys.py b/tests/test_keys.py index 12b8224f..0d41abef 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -17,7 +17,7 @@ def test_key_from_memory_with_bad_args(self): xmlsec.Key.from_memory(1, format="") def test_key_from_memory_invalid_data(self): - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load key.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load key.*'): xmlsec.Key.from_memory(b'foo', format=consts.KeyDataFormatPem) def test_key_from_file(self): @@ -29,7 +29,7 @@ def test_key_from_file_with_bad_args(self): xmlsec.Key.from_file(1, format="") def test_key_from_invalid_file(self): - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): with tempfile.NamedTemporaryFile() as tmpfile: tmpfile.write(b'foo') xmlsec.Key.from_file(tmpfile.name, format=consts.KeyDataFormatPem) @@ -42,7 +42,7 @@ def test_key_from_fileobj(self): def test_key_from_invalid_fileobj(self): with tempfile.NamedTemporaryFile(delete=False) as tmpfile: tmpfile.write(b'foo') - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'), open(tmpfile.name) as fp: + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'), open(tmpfile.name) as fp: xmlsec.Key.from_file(fp, format=consts.KeyDataFormatPem) def test_generate(self): @@ -54,7 +54,7 @@ def test_generate_with_bad_args(self): xmlsec.Key.generate(klass="", size="", type="") def test_generate_invalid_size(self): - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot generate key.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot generate key.*'): xmlsec.Key.generate(klass=consts.KeyDataAes, size=0, type=consts.KeyDataTypeSession) def test_from_binary_file(self): @@ -66,7 +66,7 @@ def test_from_binary_file_with_bad_args(self): xmlsec.Key.from_binary_file(klass="", filename=1) def test_from_invalid_binary_file(self): - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): with tempfile.NamedTemporaryFile() as tmpfile: tmpfile.write(b'foo') xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=tmpfile.name) @@ -80,7 +80,7 @@ def test_from_binary_data_with_bad_args(self): xmlsec.Key.from_binary_data(klass="", data=1) def test_from_invalid_binary_data(self): - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot read key.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=b'') def test_load_cert_from_file(self): @@ -97,7 +97,7 @@ def test_load_cert_from_file_with_bad_args(self): def test_load_cert_from_invalid_file(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): with tempfile.NamedTemporaryFile() as tmpfile: tmpfile.write(b'foo') key.load_cert_from_file(tmpfile.name, format=consts.KeyDataFormatPem) @@ -119,7 +119,7 @@ def test_load_cert_from_invalid_fileobj(self): self.assertIsNotNone(key) with tempfile.NamedTemporaryFile(delete=False) as tmpfile: tmpfile.write(b'foo') - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'), open(tmpfile.name) as fp: + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'), open(tmpfile.name) as fp: key.load_cert_from_file(fp, format=consts.KeyDataFormatPem) def test_load_cert_from_memory(self): @@ -136,7 +136,7 @@ def test_load_cert_from_memory_with_bad_args(self): def test_load_cert_from_memory_invalid_data(self): key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): key.load_cert_from_memory(b'', format=consts.KeyDataFormatPem) def test_get_name(self): @@ -190,7 +190,7 @@ def test_load_cert(self): def test_load_cert_with_bad_args(self): mngr = xmlsec.KeysManager() mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): with tempfile.NamedTemporaryFile() as tmpfile: tmpfile.write(b'foo') mngr.load_cert(tmpfile.name, format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) @@ -215,7 +215,7 @@ def test_load_cert_from_memory_with_bad_args(self): def test_load_cert_from_memory_invalid_data(self): mngr = xmlsec.KeysManager() mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) - with self.assertRaisesRegex(xmlsec.InternalError, '.*cannot load cert.*'): + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): mngr.load_cert_from_memory(b'', format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) def test_load_invalid_key(self): diff --git a/tests/test_templates.py b/tests/test_templates.py index 9475c5e4..3bae7e55 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -1,4 +1,5 @@ import unittest + from lxml import etree import xmlsec @@ -36,7 +37,7 @@ def test_ensure_key_info(self): self.assertEqual("Id", ki.get("Id")) def test_ensure_key_info_fail(self): - with self.assertRaisesRegex(xmlsec.InternalError, 'cannot ensure key info.'): + with self.assertRaisesRegex(xmlsec.Error, 'cannot ensure key info.'): xmlsec.template.ensure_key_info(etree.fromstring(b''), id="Id") def test_ensure_key_info_bad_args(self): @@ -88,7 +89,7 @@ def test_add_reference_bad_args(self): xmlsec.template.add_reference(etree.Element('root'), '') def test_add_reference_fail(self): - with self.assertRaisesRegex(xmlsec.InternalError, 'cannot add reference.'): + with self.assertRaisesRegex(xmlsec.Error, 'cannot add reference.'): xmlsec.template.add_reference(etree.Element('root'), consts.TransformSha1) def test_add_transform_bad_args(self): diff --git a/tests/test_xmlsec.py b/tests/test_xmlsec.py index 32fac69a..2d470a11 100644 --- a/tests/test_xmlsec.py +++ b/tests/test_xmlsec.py @@ -10,5 +10,5 @@ def test_reinitialize_module(self): tests don't fail, we know that the ``init()``/``shutdown()`` function pair doesn't break anything. """ - xmlsec.shutdown() - xmlsec.init() + # xmlsec.shutdown() + # xmlsec.init() From 03cd2ce07ca481f47607410a92f95f7c7f5a9009 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 22:44:58 +0200 Subject: [PATCH 200/378] switch to furo theme Signed-off-by: oleg.hoefling --- .gitignore | 2 +- .readthedocs.yml => .readthedocs.yaml | 2 +- doc/source/conf.py | 3 +-- doc/source/requirements.txt | 1 + 4 files changed, 4 insertions(+), 4 deletions(-) rename .readthedocs.yml => .readthedocs.yaml (91%) diff --git a/.gitignore b/.gitignore index 1ef359b3..669df482 100644 --- a/.gitignore +++ b/.gitignore @@ -4,7 +4,7 @@ !.travis* !.appveyor* !.git* -!.readthedocs.yml +!.readthedocs.yaml # Python /dist diff --git a/.readthedocs.yml b/.readthedocs.yaml similarity index 91% rename from .readthedocs.yml rename to .readthedocs.yaml index 4d8647be..49129b19 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yaml @@ -4,7 +4,7 @@ sphinx: configuration: doc/source/conf.py python: - version: 3.7 + version: 3.9 install: - method: pip path: . diff --git a/doc/source/conf.py b/doc/source/conf.py index bb75403b..8e39a5b6 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -4,7 +4,6 @@ import urllib.request import lxml - from docutils.nodes import reference from packaging.version import parse from sphinx.errors import ExtensionError @@ -35,7 +34,7 @@ pygments_style = 'sphinx' todo_include_todos = False -html_theme = 'nature' +html_theme = 'furo' html_static_path = [] htmlhelp_basename = 'python-xmlsecdoc' diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt index 09ff0002..6b78694a 100644 --- a/doc/source/requirements.txt +++ b/doc/source/requirements.txt @@ -2,3 +2,4 @@ lxml>=3.8 importlib_metadata;python_version < '3.8' packaging Sphinx>=3 +furo>=2021.4.11b34 From 59d6db21ee539b54cb872ffe11621cf3a721484d Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 22:57:17 +0200 Subject: [PATCH 201/378] use python 3.8 to build docs as rtd doesn't support 3.9 yet Signed-off-by: oleg.hoefling --- .readthedocs.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index 49129b19..f89031d3 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -4,7 +4,7 @@ sphinx: configuration: doc/source/conf.py python: - version: 3.9 + version: 3.8 install: - method: pip path: . From 94f0fef0a4ec78f16dcb1270deccc86f0274ef95 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 29 May 2021 00:13:38 +0200 Subject: [PATCH 202/378] reinstall custom error callback after xmlSecCryptoInit() Signed-off-by: oleg.hoefling --- src/main.c | 10 +++++----- tests/test_xmlsec.py | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/main.c b/src/main.c index c93b16d2..eef975a9 100644 --- a/src/main.c +++ b/src/main.c @@ -87,6 +87,11 @@ static int PyXmlSec_Init(void) { PyXmlSec_Free(_PYXMLSEC_FREE_ALL); return -1; } + // xmlsec will install default callback in xmlSecCryptoInit, + // overwriting any custom callbacks. + // We thus reinstall our callback now. + PyXmlSec_InstallErrorCallback(); + free_mode = _PYXMLSEC_FREE_ALL; return 0; } @@ -239,11 +244,6 @@ PYENTRY_FUNC_NAME(void) if (PyXmlSec_Init() < 0) goto ON_FAIL; - // xmlsec will install default callback in PyXmlSec_Init, - // overwriting any custom callbacks. - // We thus install our callback again now. - PyXmlSec_InstallErrorCallback(); - if (PyModule_AddStringConstant(module, "__version__", STRINGIFY(MODULE_VERSION)) < 0) goto ON_FAIL; if (PyXmlSec_InitLxmlModule() < 0) goto ON_FAIL; diff --git a/tests/test_xmlsec.py b/tests/test_xmlsec.py index 2d470a11..32fac69a 100644 --- a/tests/test_xmlsec.py +++ b/tests/test_xmlsec.py @@ -10,5 +10,5 @@ def test_reinitialize_module(self): tests don't fail, we know that the ``init()``/``shutdown()`` function pair doesn't break anything. """ - # xmlsec.shutdown() - # xmlsec.init() + xmlsec.shutdown() + xmlsec.init() From df14fa420f1978e52573188d231c49dd3d3670c9 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Thu, 27 Aug 2020 10:18:50 +0200 Subject: [PATCH 203/378] replace private type stubs with lxml-stubs Signed-off-by: oleg.hoefling --- mypy.ini | 1 - requirements-test.txt | 1 + typeshed/lxml/__init__.pyi | 0 typeshed/lxml/etree.pyi | 6 ------ 4 files changed, 1 insertion(+), 7 deletions(-) delete mode 100644 typeshed/lxml/__init__.pyi delete mode 100644 typeshed/lxml/etree.pyi diff --git a/mypy.ini b/mypy.ini index ce190e35..f404c54c 100644 --- a/mypy.ini +++ b/mypy.ini @@ -1,6 +1,5 @@ [mypy] files = src -mypy_path = typeshed/ ignore_missing_imports = False warn_unused_configs = True disallow_subclassing_any = True diff --git a/requirements-test.txt b/requirements-test.txt index dde7de3d..a2a90bbc 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,4 @@ -r requirements.txt pytest>=4.6.9 hypothesis +lxml-stubs diff --git a/typeshed/lxml/__init__.pyi b/typeshed/lxml/__init__.pyi deleted file mode 100644 index e69de29b..00000000 diff --git a/typeshed/lxml/etree.pyi b/typeshed/lxml/etree.pyi deleted file mode 100644 index 9420180f..00000000 --- a/typeshed/lxml/etree.pyi +++ /dev/null @@ -1,6 +0,0 @@ -from typing import Any - -def __getattr__(name: str) -> Any: ... # incomplete - -class _Element: - def __getattr__(self, name: str) -> Any: ... # incomplete From b31246e947caa48e1756fc111393c76c13ad015b Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 29 May 2021 11:48:52 +0200 Subject: [PATCH 204/378] update xmlsec.constants stubs Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 8be27b23..97e00544 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -1,5 +1,5 @@ import sys -from typing import NamedTuple +from typing import NamedTuple, Optional if sys.version_info >= (3, 8): from typing import Final @@ -7,12 +7,12 @@ else: from typing_extensions import Final class __KeyData(NamedTuple): # __KeyData type - href: str name: str + href: Optional[str] class __Transform(NamedTuple): # __Transform type - href: str name: str + href: Optional[str] usage: int DSigNs: Final = 'http://www.w3.org/2000/09/xmldsig#' @@ -109,7 +109,9 @@ TransformInclC14N11WithComments: Final = __Transform( 'c14n11-with-comments', 'http://www.w3.org/2006/12/xml-c14n11#WithComments', 3 ) TransformInclC14NWithComments: Final = __Transform( - 'c14n-with-comments', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments', 3 + 'c14n-with-comments', + 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments', + 3, ) TransformKWAes128: Final = __Transform('kw-aes128', 'http://www.w3.org/2001/04/xmlenc#kw-aes128', 16) TransformKWAes192: Final = __Transform('kw-aes192', 'http://www.w3.org/2001/04/xmlenc#kw-aes192', 16) From e271d8e5e957ee947c883d59ba6da0cfeedd8466 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Fri, 28 May 2021 18:09:25 +0200 Subject: [PATCH 205/378] support PEP 539 for Python>=3.7 Signed-off-by: oleg.hoefling --- src/exception.c | 26 +++++++++++++++++++++++++- 1 file changed, 25 insertions(+), 1 deletion(-) diff --git a/src/exception.c b/src/exception.c index 176cf385..06cbc61a 100644 --- a/src/exception.c +++ b/src/exception.c @@ -23,7 +23,11 @@ PyObject* PyXmlSec_Error; PyObject* PyXmlSec_InternalError; PyObject* PyXmlSec_VerificationError; +#if PY_MINOR_VERSION >= 7 +static Py_tss_t PyXmlSec_LastErrorKey; +#else static int PyXmlSec_LastErrorKey = 0; +#endif static int PyXmlSec_PrintErrorMessage = 0; @@ -71,16 +75,26 @@ static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) PyXmlSec_ErrorHolder* v; int r; - if (PyXmlSec_LastErrorKey == 0) { + #if PY_MINOR_VERSION >= 7 + if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) != 0) { + #else + if (PyXmlSec_LastErrorKey != 0) { + #endif PYXMLSEC_DEBUG("WARNING: There is no error key."); PyXmlSec_ErrorHolderFree(e); return NULL; } // get_key_value and set_key_value are gil free + #if PY_MINOR_VERSION >= 7 + v = (PyXmlSec_ErrorHolder*)PyThread_tss_get(&PyXmlSec_LastErrorKey); + //PyThread_tss_delete(&PyXmlSec_LastErrorKey); + r = PyThread_tss_set(&PyXmlSec_LastErrorKey, (void*)e); + #else v = (PyXmlSec_ErrorHolder*)PyThread_get_key_value(PyXmlSec_LastErrorKey); PyThread_delete_key_value(PyXmlSec_LastErrorKey); r = PyThread_set_key_value(PyXmlSec_LastErrorKey, (void*)e); + #endif PYXMLSEC_DEBUGF("set_key_value returns %d", r); return v; } @@ -166,7 +180,11 @@ void PyXmlSecEnableDebugTrace(int v) { } void PyXmlSec_InstallErrorCallback() { + #if PY_MINOR_VERSION >= 7 + if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) != 0) { + #else if (PyXmlSec_LastErrorKey != 0) { + #endif xmlSecErrorsSetCallback(PyXmlSec_ErrorCallback); } } @@ -190,8 +208,14 @@ int PyXmlSec_ExceptionsModule_Init(PyObject* package) { if (PyModule_AddObject(package, "InternalError", PyXmlSec_InternalError) < 0) goto ON_FAIL; if (PyModule_AddObject(package, "VerificationError", PyXmlSec_VerificationError) < 0) goto ON_FAIL; + #if PY_MINOR_VERSION >= 7 + if (PyThread_tss_create(&PyXmlSec_LastErrorKey)) { + PyXmlSec_InstallErrorCallback(); + } + #else PyXmlSec_LastErrorKey = PyThread_create_key(); PyXmlSec_InstallErrorCallback(); + #endif return 0; From 461541eed4f86df68ad6df11fca4c16c0cd09074 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 29 May 2021 13:45:06 +0200 Subject: [PATCH 206/378] avoid incompatible pointer type warning Signed-off-by: oleg.hoefling --- src/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.c b/src/keys.c index 8e065ea0..46dbf651 100644 --- a/src/keys.c +++ b/src/keys.c @@ -453,7 +453,7 @@ static int PyXmlSec_KeyNameSet(PyObject* self, PyObject* value, void* closure) { } if (value == NULL) { - if (xmlSecKeySetName(key->handle, value) < 0) { + if (xmlSecKeySetName(key->handle, NULL) < 0) { PyXmlSec_SetLastError("cannot delete name"); return -1; } From 4d108dd9e750791138edebf5ba786bf04d692e7c Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 5 Jun 2021 00:29:56 +0200 Subject: [PATCH 207/378] fix error key presence check Signed-off-by: oleg.hoefling --- src/exception.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/exception.c b/src/exception.c index 06cbc61a..ac0e44ee 100644 --- a/src/exception.c +++ b/src/exception.c @@ -76,9 +76,9 @@ static PyXmlSec_ErrorHolder* PyXmlSec_ExchangeLastError(PyXmlSec_ErrorHolder* e) int r; #if PY_MINOR_VERSION >= 7 - if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) != 0) { + if (PyThread_tss_is_created(&PyXmlSec_LastErrorKey) == 0) { #else - if (PyXmlSec_LastErrorKey != 0) { + if (PyXmlSec_LastErrorKey == 0) { #endif PYXMLSEC_DEBUG("WARNING: There is no error key."); PyXmlSec_ErrorHolderFree(e); @@ -209,7 +209,7 @@ int PyXmlSec_ExceptionsModule_Init(PyObject* package) { if (PyModule_AddObject(package, "VerificationError", PyXmlSec_VerificationError) < 0) goto ON_FAIL; #if PY_MINOR_VERSION >= 7 - if (PyThread_tss_create(&PyXmlSec_LastErrorKey)) { + if (PyThread_tss_create(&PyXmlSec_LastErrorKey) == 0) { PyXmlSec_InstallErrorCallback(); } #else From 8b2f5a53e091e6fda636c8e2605a46254d542dca Mon Sep 17 00:00:00 2001 From: visuman Date: Thu, 10 Jun 2021 16:12:43 +0530 Subject: [PATCH 208/378] fix warning related to use of dash seperated values Fixes https://github.com/mehcode/python-xmlsec/issues/182 Making changes in setup.cfg to fix the warning related to use of dash-seperated values --- setup.cfg | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/setup.cfg b/setup.cfg index ada30e9b..c61fd65b 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,9 +1,9 @@ [metadata] -description-file = README.rst +description_file = README.rst [bdist_rpm] release = 1 -build-requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel +build_requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel group = Development/Libraries requires = xmlsec1 xmlsec1-openssl @@ -13,7 +13,7 @@ build-dir = doc/build all_files = 1 [upload_docs] -upload-dir = doc/build/html +upload_dir = doc/build/html [flake8] max-line-length = 130 From 2460f50a51ae3719cdab5dbeabc18b8ef8c71f52 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 12 Jun 2021 14:06:51 +0200 Subject: [PATCH 209/378] add XMLSEC_NO_MD5 check Signed-off-by: oleg.hoefling --- src/constants.c | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/constants.c b/src/constants.c index 8c17e389..34c81b29 100644 --- a/src/constants.c +++ b/src/constants.c @@ -507,7 +507,10 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformEcdsaSha512, "ECDSA_SHA512"); #endif +#ifndef XMLSEC_NO_MD5 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacMd5, "HMAC_MD5"); +#endif + #ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacRipemd160, "HMAC_RIPEMD160"); #endif @@ -517,7 +520,10 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha384, "HMAC_SHA384"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformHmacSha512, "HMAC_SHA512"); +#ifndef XMLSEC_NO_MD5 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaMd5, "RSA_MD5"); +#endif + #ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaRipemd160, "RSA_RIPEMD160"); #endif @@ -529,7 +535,10 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaPkcs1, "RSA_PKCS1"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRsaOaep, "RSA_OAEP"); +#ifndef XMLSEC_NO_MD5 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformMd5, "MD5"); +#endif + #ifndef XMLSEC_NO_RIPEMD160 PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformRipemd160, "RIPEMD160"); #endif From 80c5fb3173d6eb07d6e065ba7f48cf6bf52c87b6 Mon Sep 17 00:00:00 2001 From: Tonye Jack Date: Mon, 26 Jul 2021 15:40:59 -0400 Subject: [PATCH 210/378] Added missing pkg-config dependency. This seems to be required when using python3-slim debian image. Resolves ```#10 182.5 Building wheels for collected packages: xmlsec #10 182.5 Building wheel for xmlsec (PEP 517): started #10 182.9 Building wheel for xmlsec (PEP 517): finished with status 'error' #10 182.9 ERROR: Command errored out with exit status 1: #10 182.9 command: /venv/bin/python3.6 /venv/lib/python3.6/site-packages/pip/_vendor/pep517/in_process/_in_process.py build_wheel /tmp/tmpr1_o4zak #10 182.9 cwd: /tmp/pip-install-amr3abkp/xmlsec_201c200071954684a9d29b2158df27bc #10 182.9 Complete output (20 lines): #10 182.9 /tmp/pip-build-env-hr3wr4uf/overlay/lib/python3.6/site-packages/setuptools/dist.py:700: UserWarning: Usage of dash-separated 'description-file' will not be supported in future versions. Please use the underscore name 'description_file' instead #10 182.9 % (opt, underscore_opt)) #10 182.9 /tmp/pip-build-env-hr3wr4uf/overlay/lib/python3.6/site-packages/setuptools/dist.py:700: UserWarning: Usage of dash-separated 'build-requires' will not be supported in future versions. Please use the underscore name 'build_requires' instead #10 182.9 % (opt, underscore_opt)) #10 182.9 /tmp/pip-build-env-hr3wr4uf/overlay/lib/python3.6/site-packages/setuptools/dist.py:700: UserWarning: Usage of dash-separated 'upload-dir' will not be supported in future versions. Please use the underscore name 'upload_dir' instead #10 182.9 % (opt, underscore_opt)) #10 182.9 running bdist_wheel #10 182.9 running build #10 182.9 running build_py #10 182.9 package init file 'src/xmlsec/__init__.py' not found (or not a regular file) #10 182.9 creating build #10 182.9 creating build/lib.linux-x86_64-3.6 #10 182.9 creating build/lib.linux-x86_64-3.6/xmlsec #10 182.9 copying src/xmlsec/py.typed -> build/lib.linux-x86_64-3.6/xmlsec #10 182.9 copying src/xmlsec/constants.pyi -> build/lib.linux-x86_64-3.6/xmlsec #10 182.9 copying src/xmlsec/template.pyi -> build/lib.linux-x86_64-3.6/xmlsec #10 182.9 copying src/xmlsec/__init__.pyi -> build/lib.linux-x86_64-3.6/xmlsec #10 182.9 copying src/xmlsec/tree.pyi -> build/lib.linux-x86_64-3.6/xmlsec #10 182.9 running build_ext #10 182.9 error: Unable to invoke pkg-config. #10 182.9 ---------------------------------------- #10 182.9 ERROR: Failed building wheel for xmlsec #10 182.9 ERROR: Could not build wheels for xmlsec which use PEP 517 and cannot be installed directly #10 182.9 Failed to build xmlsec``` --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 22235af4..1543f821 100644 --- a/README.rst +++ b/README.rst @@ -53,7 +53,7 @@ Linux (Debian) .. code-block:: bash - apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl + apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl Note: There is no required version of LibXML2 for Ubuntu Precise, From 8ed003c2887c46d47a84bbd31bcc05a3559479db Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 26 Jul 2021 17:31:55 +0100 Subject: [PATCH 211/378] add changelog to project_urls --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 2838fe84..541eb029 100644 --- a/setup.py +++ b/setup.py @@ -415,6 +415,7 @@ def prepare_static_build_linux(self): project_urls={ 'Documentation': 'https://xmlsec.readthedocs.io', 'Source': 'https://github.com/mehcode/python-xmlsec', + 'Changelog': 'https://github.com/mehcode/python-xmlsec/releases', }, license='MIT', keywords=['xmlsec'], From 73711a8c70387fb3a9b42d6c6a35fe1ca9d1d0ef Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Mon, 26 Jul 2021 17:09:13 +0100 Subject: [PATCH 212/378] First cut of registering Python callbacks for xmlsec This implementation uses a global linked-list structure to hold onto the Python callbacks and registers a single C wrapper callback with xmlsec to dispatch xmlsec's calling back to the appropriate Python function. This was the simplest way I could think to emulate dynamically wrapping the Python calls in C code, because C doesn't have closures. A potential downside is that the state is all very global. Perhaps, however, that's no worse than the very global set of callbacks that xmlsec holds onto itself, so long as we don't have any strange threading stuff going on. In order to accommodate client code potentially interleaving registrations of the default callbacks in between their own callbacks, the linked list structure can have nodes with NULL function pointers in it, such that when iterating through Python callbacks we can suspend our iteration and delegate back to the defaults at the appropriate point. As such, we always actually have the Python binding's C callbacks registered with xmlsec, and every time we get asked to register the default callbacks, we note a NULL function pointer and then re-register our C callbacks. --- src/main.c | 242 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 242 insertions(+) diff --git a/src/main.c b/src/main.c index eef975a9..ec97ec3b 100644 --- a/src/main.c +++ b/src/main.c @@ -15,6 +15,7 @@ #include #include #include +#include #define _PYXMLSEC_FREE_NONE 0 #define _PYXMLSEC_FREE_XMLSEC 1 @@ -133,6 +134,229 @@ static PyObject* PyXmlSec_PyEnableDebugOutput(PyObject *self, PyObject* args, Py Py_RETURN_NONE; } +// NB: This whole thing assumes that the `xmlsec` callbacks are not re-entrant +// (i.e. that xmlsec won't come across a link in the reference it's processing +// and try to open that with these callbacks too). +typedef struct CbList { + PyObject* match_cb; + PyObject* open_cb; + PyObject* read_cb; + PyObject* close_cb; + struct CbList* next; +} CbList; + +static CbList* registered_callbacks = NULL; +static CbList* rcb_tail = NULL; + +static void RCBListAppend(CbList* cb_list_item) { + if (registered_callbacks == NULL) { + registered_callbacks = cb_list_item; + } else { + rcb_tail->next = cb_list_item; + } + rcb_tail = cb_list_item; +} + +static void RCBListClear() { + CbList* cb_list_item = registered_callbacks; + while (cb_list_item) { + Py_XDECREF(cb_list_item->match_cb); + Py_XDECREF(cb_list_item->open_cb); + Py_XDECREF(cb_list_item->read_cb); + Py_XDECREF(cb_list_item->close_cb); + CbList* next = cb_list_item->next; + free(cb_list_item); + cb_list_item = next; + } + registered_callbacks = NULL; + rcb_tail = NULL; +} + +// The currently executing set of Python callbacks: +static CbList* cur_cb_list_item = NULL; + +static int PyXmlSec_MatchCB(const char* filename) { + if (!cur_cb_list_item) { + cur_cb_list_item = registered_callbacks; + } + while (cur_cb_list_item && !cur_cb_list_item->match_cb) { + // Spool past any default callback placeholders executed since we were + // last called back: + cur_cb_list_item = cur_cb_list_item->next; + } + PyGILState_STATE state = PyGILState_Ensure(); + PyObject* args = Py_BuildValue("(y)", filename); + while (cur_cb_list_item && cur_cb_list_item->match_cb) { + PyObject* result = PyObject_CallObject(cur_cb_list_item->match_cb, args); + if (result && PyObject_IsTrue(result)) { + Py_DECREF(result); + Py_DECREF(args); + PyGILState_Release(state); + return 1; + } + cur_cb_list_item = cur_cb_list_item->next; + } + // FIXME: why does having this decref of args cause a segfault?! + Py_DECREF(args); + PyGILState_Release(state); + return 0; +} + +static void* PyXmlSec_OpenCB(const char* filename) { + PyGILState_STATE state = PyGILState_Ensure(); + + // NB: Assumes the match callback left the current callback list item in the + // right place: + PyObject* args = Py_BuildValue("(y)", filename); + PyObject* result = PyObject_CallObject(cur_cb_list_item->open_cb, args); + Py_DECREF(args); + + PyGILState_Release(state); + return result; +} + +static int PyXmlSec_ReadCB(void* context, char* buffer, int len) { + PyGILState_STATE state = PyGILState_Ensure(); + + // NB: Assumes the match callback left the current callback list item in the + // right place: + PyObject* py_buffer = PyMemoryView_FromMemory(buffer, (Py_ssize_t) len, PyBUF_WRITE); + PyObject* args = Py_BuildValue("(OO)", context, py_buffer); + PyObject* py_bytes_read = PyObject_CallObject(cur_cb_list_item->read_cb, args); + Py_DECREF(args); + Py_DECREF(py_buffer); + int result; + if (py_bytes_read && PyLong_Check(py_bytes_read)) { + result = (int)PyLong_AsLong(py_bytes_read); + Py_DECREF(py_bytes_read); + } else { + result = EOF; + } + + PyGILState_Release(state); + return result; +} + +static int PyXmlSec_CloseCB(void* context) { + PyGILState_STATE state = PyGILState_Ensure(); + + PyObject* args = Py_BuildValue("(O)", context); + PyObject* result = PyObject_CallObject(cur_cb_list_item->close_cb, args); + Py_DECREF(args); + Py_DECREF(context); + Py_DECREF(result); + + PyGILState_Release(state); + // We reset `cur_cb_list_item` because we've finished processing the set of + // callbacks that was matched + cur_cb_list_item = NULL; + return 0; +} + +static char PyXmlSec_PyIOCleanupCallbacks__doc__[] = \ + "Unregister globally all sets of IO callbacks from xmlsec."; +static PyObject* PyXmlSec_PyIOCleanupCallbacks(PyObject *self) { + xmlSecIOCleanupCallbacks(); + // We always have callbacks registered to delegate to any Python callbacks + // we have registered within these bindings: + if (xmlSecIORegisterCallbacks( + PyXmlSec_MatchCB, PyXmlSec_OpenCB, PyXmlSec_ReadCB, + PyXmlSec_CloseCB) < 0) { + return NULL; + }; + RCBListClear(); + Py_RETURN_NONE; +} + +static char PyXmlSec_PyIORegisterDefaultCallbacks__doc__[] = \ + "Register globally xmlsec's own default set of IO callbacks."; +static PyObject* PyXmlSec_PyIORegisterDefaultCallbacks(PyObject *self) { + if (xmlSecIORegisterDefaultCallbacks() < 0) { + return NULL; + } + // We place a nulled item on the callback list to represent whenever the + // default callbacks are going to be invoked: + CbList* cb_list_item = malloc(sizeof(CbList)); + if (cb_list_item == NULL) { + return NULL; + } + cb_list_item->match_cb = NULL; + cb_list_item->open_cb = NULL; + cb_list_item->read_cb = NULL; + cb_list_item->close_cb = NULL; + cb_list_item->next = NULL; + RCBListAppend(cb_list_item); + // We need to make sure we can continue trying to match futher Python + // callbacks if the default callback doesn't match: + if (xmlSecIORegisterCallbacks( + PyXmlSec_MatchCB, PyXmlSec_OpenCB, PyXmlSec_ReadCB, + PyXmlSec_CloseCB) < 0) { + return NULL; + }; + Py_RETURN_NONE; +} + +static char PyXmlSec_PyIORegisterCallbacks__doc__[] = \ + "Register globally a custom set of IO callbacks with xmlsec.\n\n" + ":param callable input_match_callback: A callable that takes a filename `bytestring` and " + "returns a boolean as to whether the other callbacks in this set can handle that name.\n" + ":param callable input_open_callback: A callable that takes a filename and returns some " + "context object (e.g. a file object) that the remaining callables in this set will be passed " + "during handling.\n" + // FIXME: How do we handle failures in ^^ (e.g. can't find the file)? + ":param callable input_read_callback: A callable that that takes the context object from the " + "open callback and a buffer, and should fill the buffer with data (e.g. BytesIO.readinto()). " + "xmlsec will call this function several times until there is no more data returned.\n" + ":param callable input_close_callback: A callable that takes the context object from the " + "open callback and can do any resource cleanup necessary.\n" + ; +static PyObject* PyXmlSec_PyIORegisterCallbacks(PyObject *self, PyObject *args, PyObject *kwargs) { + static char *kwlist[] = { + "input_match_callback", + "input_open_callback", + "input_read_callback", + "input_close_callback", + NULL + }; + CbList* cb_list_item = malloc(sizeof(CbList)); + if (cb_list_item == NULL) { + return NULL; + } + if (!PyArg_ParseTupleAndKeywords( + args, kwargs, "OOOO:register_callbacks", kwlist, + &cb_list_item->match_cb, &cb_list_item->open_cb, &cb_list_item->read_cb, + &cb_list_item->close_cb)) { + free(cb_list_item); + return NULL; + } + if (!PyCallable_Check(cb_list_item->match_cb)) { + PyErr_SetString(PyExc_TypeError, "input_match_callback must be a callable"); + return NULL; + } + if (!PyCallable_Check(cb_list_item->open_cb)) { + PyErr_SetString(PyExc_TypeError, "input_open_callback must be a callable"); + return NULL; + } + if (!PyCallable_Check(cb_list_item->read_cb)) { + PyErr_SetString(PyExc_TypeError, "input_read_callback must be a callable"); + return NULL; + } + if (!PyCallable_Check(cb_list_item->close_cb)) { + PyErr_SetString(PyExc_TypeError, "input_close_callback must be a callable"); + return NULL; + } + Py_INCREF(cb_list_item->match_cb); + Py_INCREF(cb_list_item->open_cb); + Py_INCREF(cb_list_item->read_cb); + Py_INCREF(cb_list_item->close_cb); + cb_list_item->next = NULL; + RCBListAppend(cb_list_item); + // NB: We don't need to register the callbacks with `xmlsec` here, because + // we've already registered our helper functions that will trawl through our + // list of callbacks. + Py_RETURN_NONE; +} + static char PyXmlSec_PyBase64DefaultLineSize__doc__[] = \ "base64_default_line_size(size = None)\n" "Configures the default maximum columns size for base64 encoding.\n\n" @@ -181,6 +405,24 @@ static PyMethodDef PyXmlSec_MainMethods[] = { METH_VARARGS|METH_KEYWORDS, PyXmlSec_PyEnableDebugOutput__doc__ }, + { + "cleanup_callbacks", + (PyCFunction)PyXmlSec_PyIOCleanupCallbacks, + METH_NOARGS, + PyXmlSec_PyIOCleanupCallbacks__doc__ + }, + { + "register_default_callbacks", + (PyCFunction)PyXmlSec_PyIORegisterDefaultCallbacks, + METH_NOARGS, + PyXmlSec_PyIORegisterDefaultCallbacks__doc__ + }, + { + "register_callbacks", + (PyCFunction)PyXmlSec_PyIORegisterCallbacks, + METH_VARARGS|METH_KEYWORDS, + PyXmlSec_PyIORegisterCallbacks__doc__ + }, { "base64_default_line_size", (PyCFunction)PyXmlSec_PyBase64DefaultLineSize, From 09665dfa38ef10e13edf387a915ae273b71508a4 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Tue, 27 Jul 2021 10:18:10 +0100 Subject: [PATCH 213/378] Improve memory cleanup --- src/main.c | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/main.c b/src/main.c index ec97ec3b..205174e6 100644 --- a/src/main.c +++ b/src/main.c @@ -194,9 +194,9 @@ static int PyXmlSec_MatchCB(const char* filename) { PyGILState_Release(state); return 1; } + Py_XDECREF(result); cur_cb_list_item = cur_cb_list_item->next; } - // FIXME: why does having this decref of args cause a segfault?! Py_DECREF(args); PyGILState_Release(state); return 0; @@ -228,10 +228,10 @@ static int PyXmlSec_ReadCB(void* context, char* buffer, int len) { int result; if (py_bytes_read && PyLong_Check(py_bytes_read)) { result = (int)PyLong_AsLong(py_bytes_read); - Py_DECREF(py_bytes_read); } else { result = EOF; } + Py_XDECREF(py_bytes_read); PyGILState_Release(state); return result; @@ -331,18 +331,22 @@ static PyObject* PyXmlSec_PyIORegisterCallbacks(PyObject *self, PyObject *args, } if (!PyCallable_Check(cb_list_item->match_cb)) { PyErr_SetString(PyExc_TypeError, "input_match_callback must be a callable"); + free(cb_list_item); return NULL; } if (!PyCallable_Check(cb_list_item->open_cb)) { PyErr_SetString(PyExc_TypeError, "input_open_callback must be a callable"); + free(cb_list_item); return NULL; } if (!PyCallable_Check(cb_list_item->read_cb)) { PyErr_SetString(PyExc_TypeError, "input_read_callback must be a callable"); + free(cb_list_item); return NULL; } if (!PyCallable_Check(cb_list_item->close_cb)) { PyErr_SetString(PyExc_TypeError, "input_close_callback must be a callable"); + free(cb_list_item); return NULL; } Py_INCREF(cb_list_item->match_cb); From 12690e865c91414bd2f60f5c4c1864408001396c Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Thu, 29 Jul 2021 10:37:17 +0100 Subject: [PATCH 214/378] Add signatures for new functions to __init__.pyi --- src/xmlsec/__init__.pyi | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 9ec147e9..93ff8658 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,5 +1,7 @@ import sys -from typing import AnyStr, IO, Iterable, Optional, Type, TypeVar, Union, overload +from typing import ( + Any, AnyStr, Callable, IO, Iterable, Optional, Type, TypeVar, Union, + overload) from lxml.etree import _Element @@ -24,6 +26,14 @@ _K = TypeVar('_K', bound=Key) def enable_debug_trace(enabled: bool = ...) -> None: ... def init() -> None: ... def shutdown() -> None: ... +def cleanup_callbacks() -> None: ... +def register_default_callbacks() -> None: ... +def register_callbacks( + input_match_callback: Callable[[bytes], bool], + input_open_callback: Callable[[bytes], Any], + input_read_callback: Callable[[Any, memoryview], int], + input_close_callback: Callable[[Any], None], +) -> None: ... @overload def base64_default_line_size() -> int: ... @overload From 91730b25986284304da480c62f4f1dbf6cd44de0 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Fri, 30 Jul 2021 11:02:00 +0100 Subject: [PATCH 215/378] Test and fix IO callback bindings Turns out the `xmlSecAllIOCallbacks` pointer list yields the stored callbacks in reverse, _and_ the default callbacks steal everything ( libxml2's `xmlFileMatch` is literally defined as `return(1)`! So we - Simplify our linked list of sets of Python callbacks to cons, rather than append - Don't bother trying to track interleaving default callbacks and Python callbacks, because `cur_cb_list_item` would get left in a bad state when the default matched. - Instead, drop all callbacks added prior to the default callbacks being added. Tests-wise, there are a lot of failures relating to unreferenced objects and/or memory leaks. However, as an example the top test is completely commented out right now (i.e. doesn't do anything with the library), so I'm a bit stuck as to how to grapple with that! --- src/main.c | 62 +++++++-------------- tests/test_main.py | 134 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 154 insertions(+), 42 deletions(-) diff --git a/src/main.c b/src/main.c index 205174e6..41f5e5fc 100644 --- a/src/main.c +++ b/src/main.c @@ -146,47 +146,34 @@ typedef struct CbList { } CbList; static CbList* registered_callbacks = NULL; -static CbList* rcb_tail = NULL; -static void RCBListAppend(CbList* cb_list_item) { - if (registered_callbacks == NULL) { - registered_callbacks = cb_list_item; - } else { - rcb_tail->next = cb_list_item; - } - rcb_tail = cb_list_item; +static void RCBListCons(CbList* cb_list_item) { + cb_list_item->next = registered_callbacks; + registered_callbacks = cb_list_item; } static void RCBListClear() { CbList* cb_list_item = registered_callbacks; while (cb_list_item) { - Py_XDECREF(cb_list_item->match_cb); - Py_XDECREF(cb_list_item->open_cb); - Py_XDECREF(cb_list_item->read_cb); - Py_XDECREF(cb_list_item->close_cb); + Py_DECREF(cb_list_item->match_cb); + Py_DECREF(cb_list_item->open_cb); + Py_DECREF(cb_list_item->read_cb); + Py_DECREF(cb_list_item->close_cb); CbList* next = cb_list_item->next; free(cb_list_item); cb_list_item = next; } registered_callbacks = NULL; - rcb_tail = NULL; } // The currently executing set of Python callbacks: -static CbList* cur_cb_list_item = NULL; +static CbList* cur_cb_list_item; static int PyXmlSec_MatchCB(const char* filename) { - if (!cur_cb_list_item) { - cur_cb_list_item = registered_callbacks; - } - while (cur_cb_list_item && !cur_cb_list_item->match_cb) { - // Spool past any default callback placeholders executed since we were - // last called back: - cur_cb_list_item = cur_cb_list_item->next; - } + cur_cb_list_item = registered_callbacks; PyGILState_STATE state = PyGILState_Ensure(); PyObject* args = Py_BuildValue("(y)", filename); - while (cur_cb_list_item && cur_cb_list_item->match_cb) { + while (cur_cb_list_item) { PyObject* result = PyObject_CallObject(cur_cb_list_item->match_cb, args); if (result && PyObject_IsTrue(result)) { Py_DECREF(result); @@ -247,9 +234,6 @@ static int PyXmlSec_CloseCB(void* context) { Py_DECREF(result); PyGILState_Release(state); - // We reset `cur_cb_list_item` because we've finished processing the set of - // callbacks that was matched - cur_cb_list_item = NULL; return 0; } @@ -263,7 +247,7 @@ static PyObject* PyXmlSec_PyIOCleanupCallbacks(PyObject *self) { PyXmlSec_MatchCB, PyXmlSec_OpenCB, PyXmlSec_ReadCB, PyXmlSec_CloseCB) < 0) { return NULL; - }; + } RCBListClear(); Py_RETURN_NONE; } @@ -271,23 +255,17 @@ static PyObject* PyXmlSec_PyIOCleanupCallbacks(PyObject *self) { static char PyXmlSec_PyIORegisterDefaultCallbacks__doc__[] = \ "Register globally xmlsec's own default set of IO callbacks."; static PyObject* PyXmlSec_PyIORegisterDefaultCallbacks(PyObject *self) { + // NB: The default callbacks (specifically libxml2's `xmlFileMatch`) always + // match, and callbacks are called in the reverse order to that which they + // were added. So, there's no point in holding onto any previously registered + // callbacks, because they will never be run: + xmlSecIOCleanupCallbacks(); + RCBListClear(); if (xmlSecIORegisterDefaultCallbacks() < 0) { return NULL; } - // We place a nulled item on the callback list to represent whenever the - // default callbacks are going to be invoked: - CbList* cb_list_item = malloc(sizeof(CbList)); - if (cb_list_item == NULL) { - return NULL; - } - cb_list_item->match_cb = NULL; - cb_list_item->open_cb = NULL; - cb_list_item->read_cb = NULL; - cb_list_item->close_cb = NULL; - cb_list_item->next = NULL; - RCBListAppend(cb_list_item); - // We need to make sure we can continue trying to match futher Python - // callbacks if the default callback doesn't match: + // We need to make sure we can continue trying to match any newly added + // Python callbacks: if (xmlSecIORegisterCallbacks( PyXmlSec_MatchCB, PyXmlSec_OpenCB, PyXmlSec_ReadCB, PyXmlSec_CloseCB) < 0) { @@ -354,7 +332,7 @@ static PyObject* PyXmlSec_PyIORegisterCallbacks(PyObject *self, PyObject *args, Py_INCREF(cb_list_item->read_cb); Py_INCREF(cb_list_item->close_cb); cb_list_item->next = NULL; - RCBListAppend(cb_list_item); + RCBListCons(cb_list_item); // NB: We don't need to register the callbacks with `xmlsec` here, because // we've already registered our helper functions that will trawl through our // list of callbacks. diff --git a/tests/test_main.py b/tests/test_main.py index a0d144ca..ac19f3fc 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,4 +1,10 @@ import xmlsec +from xmlsec import constants as consts + +from io import BytesIO + +from hypothesis import given, strategies +import pytest from tests import base @@ -30,3 +36,131 @@ def test_set_base64_default_line_size_rejects_negative_values(self): with self.assertRaises(ValueError): xmlsec.base64_default_line_size(-1) self.assertEqual(xmlsec.base64_default_line_size(), size) + + +class TestCallbacks(base.TestMemoryLeaks): + def setUp(self): + super().setUp() + xmlsec.cleanup_callbacks() + + @given(funcs=strategies.lists( + strategies.sampled_from([ + lambda: None + # xmlsec.cleanup_callbacks, + # xmlsec.register_default_callbacks, + ]) + )) + def test_arbitrary_cleaning_and_default_callback_registration(self, funcs): + # FIXME: This test seems to detelct unreferenced objects and memory + # leaks even if it never does anything! + pass + # for f in funcs: + # f() + + def _sign_doc(self): + root = self.load_xml("doc.xml") + sign = xmlsec.template.create( + root, + c14n_method=consts.TransformExclC14N, + sign_method=consts.TransformRsaSha1 + ) + xmlsec.template.add_reference( + sign, consts.TransformSha1, uri="cid:123456") + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_file( + self.path("rsakey.pem"), format=consts.KeyDataFormatPem + ) + ctx.sign(sign) + return sign + + def _expect_sign_failure(self): + exc_info = pytest.raises(xmlsec.Error, self._sign_doc) + self.assertEqual(exc_info.value.args, (1, 'failed to sign')) + + def _register_mismatch_callbacks(self, match_cb=lambda filename: False): + xmlsec.register_callbacks( + match_cb, + lambda filename: None, + lambda none, buf: 0, + lambda none: None, + ) + + def _register_match_callbacks(self): + xmlsec.register_callbacks( + lambda filename: filename == b'cid:123456', + lambda filename: BytesIO(b''), + lambda bio, buf: bio.readinto(buf), + lambda bio: bio.close(), + ) + + def _find(self, elem, *tags): + for tag in tags: + elem = elem.find( + '{{http://www.w3.org/2000/09/xmldsig#}}{}'.format(tag)) + return elem + + def _verify_external_data_signature(self): + signature = self._sign_doc() + digest = self._find( + signature, 'SignedInfo', 'Reference', 'DigestValue' + ).text + self.assertEqual(digest, 'VihZwVMGJ48NsNl7ertVHiURXk8=') + + def test_sign_external_data_no_callbacks_fails(self): + self._expect_sign_failure() + + def test_sign_external_data_default_callbacks_fails(self): + xmlsec.register_default_callbacks() + self._expect_sign_failure() + + def test_sign_external_data_no_matching_callbacks_fails(self): + self._register_mismatch_callbacks() + self._expect_sign_failure() + + def test_sign_data_from_callbacks(self): + self._register_match_callbacks() + self._verify_external_data_signature() + + @given( + num_prior_mismatches=strategies.integers(min_value=1, max_value=50), + num_post_mismatches=strategies.integers(min_value=1, max_value=50), + ) + def test_sign_data_not_first_callback( + self, num_prior_mismatches, num_post_mismatches + ): + bad_match_calls = 0 + + def match_cb(filename): + nonlocal bad_match_calls + bad_match_calls += 1 + False + + for _ in range(num_post_mismatches): + self._register_mismatch_callbacks(match_cb) + + self._register_match_callbacks() + + for _ in range(num_prior_mismatches): + self._register_mismatch_callbacks() + + self._verify_external_data_signature() + self.assertEqual(bad_match_calls, 0) + + def test_failed_sign_because_default_callbacks(self): + mismatch_calls = 0 + + def mismatch_cb(filename): + nonlocal mismatch_calls + mismatch_calls += 1 + False + + # NB: These first two sets of callbacks should never get called, + # because the default callbacks always match beforehand: + self._register_match_callbacks() + self._register_mismatch_callbacks(mismatch_cb) + xmlsec.register_default_callbacks() + self._register_mismatch_callbacks(mismatch_cb) + self._register_mismatch_callbacks(mismatch_cb) + self._expect_sign_failure() + self.assertEqual(mismatch_calls, 2) From 5f65a37285e07432b70f13337eaa47706a9b5728 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Mon, 2 Aug 2021 15:26:42 +0100 Subject: [PATCH 216/378] Remove hypothesis from callback testing --- tests/test_main.py | 27 +++------------------------ 1 file changed, 3 insertions(+), 24 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index ac19f3fc..c57b6a9f 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -3,7 +3,6 @@ from io import BytesIO -from hypothesis import given, strategies import pytest from tests import base @@ -43,20 +42,6 @@ def setUp(self): super().setUp() xmlsec.cleanup_callbacks() - @given(funcs=strategies.lists( - strategies.sampled_from([ - lambda: None - # xmlsec.cleanup_callbacks, - # xmlsec.register_default_callbacks, - ]) - )) - def test_arbitrary_cleaning_and_default_callback_registration(self, funcs): - # FIXME: This test seems to detelct unreferenced objects and memory - # leaks even if it never does anything! - pass - # for f in funcs: - # f() - def _sign_doc(self): root = self.load_xml("doc.xml") sign = xmlsec.template.create( @@ -122,13 +107,7 @@ def test_sign_data_from_callbacks(self): self._register_match_callbacks() self._verify_external_data_signature() - @given( - num_prior_mismatches=strategies.integers(min_value=1, max_value=50), - num_post_mismatches=strategies.integers(min_value=1, max_value=50), - ) - def test_sign_data_not_first_callback( - self, num_prior_mismatches, num_post_mismatches - ): + def test_sign_data_not_first_callback(self): bad_match_calls = 0 def match_cb(filename): @@ -136,12 +115,12 @@ def match_cb(filename): bad_match_calls += 1 False - for _ in range(num_post_mismatches): + for _ in range(2): self._register_mismatch_callbacks(match_cb) self._register_match_callbacks() - for _ in range(num_prior_mismatches): + for _ in range(2): self._register_mismatch_callbacks() self._verify_external_data_signature() From a2c2b7582cad64a201688a2d67b2f62bd8846257 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Mon, 16 Aug 2021 16:38:51 +0100 Subject: [PATCH 217/378] Use unittest's exception assertion because pytest.raises leaves junk around! --- tests/test_main.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index c57b6a9f..40889621 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -60,8 +60,8 @@ def _sign_doc(self): return sign def _expect_sign_failure(self): - exc_info = pytest.raises(xmlsec.Error, self._sign_doc) - self.assertEqual(exc_info.value.args, (1, 'failed to sign')) + with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'): + self._sign_doc() def _register_mismatch_callbacks(self, match_cb=lambda filename: False): xmlsec.register_callbacks( From ce90c06a32556cf79b0fc224b9ebe63d3d08c8e8 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Fri, 20 Aug 2021 10:48:38 +0100 Subject: [PATCH 218/378] Remove unused import --- tests/test_main.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_main.py b/tests/test_main.py index 40889621..556e0161 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,9 +1,9 @@ +from lxml import etree import xmlsec from xmlsec import constants as consts from io import BytesIO -import pytest from tests import base From f17f4b9c957a18e9210c72162f06cfa7414b086e Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Fri, 20 Aug 2021 10:49:31 +0100 Subject: [PATCH 219/378] Use xpath to traverse signature structure in tests It seems to be way more robust across library versions. --- tests/test_main.py | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 556e0161..2c57f3e4 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -80,10 +80,15 @@ def _register_match_callbacks(self): ) def _find(self, elem, *tags): - for tag in tags: - elem = elem.find( - '{{http://www.w3.org/2000/09/xmldsig#}}{}'.format(tag)) - return elem + try: + return elem.xpath( + './' + '/'.join('xmldsig:{}'.format(tag) for tag in tags), + namespaces={ + 'xmldsig': 'http://www.w3.org/2000/09/xmldsig#', + } + )[0] + except IndexError as e: + raise KeyError(tags) from e def _verify_external_data_signature(self): signature = self._sign_doc() From 7b41f2710e923e6f51087df9d05039d2f0b66369 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Mon, 23 Aug 2021 10:13:33 +0100 Subject: [PATCH 220/378] Remove unused import --- tests/test_main.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/test_main.py b/tests/test_main.py index 2c57f3e4..c3271139 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,4 +1,3 @@ -from lxml import etree import xmlsec from xmlsec import constants as consts From 9798d6d99ebf502152f5432589a50bc82fd69264 Mon Sep 17 00:00:00 2001 From: Paul Weaver Date: Mon, 23 Aug 2021 10:13:50 +0100 Subject: [PATCH 221/378] Test TypeError when setting non-callable callbacks --- tests/test_main.py | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index c3271139..648aa5b0 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -62,13 +62,16 @@ def _expect_sign_failure(self): with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'): self._sign_doc() - def _register_mismatch_callbacks(self, match_cb=lambda filename: False): - xmlsec.register_callbacks( + def _mismatch_callbacks(self, match_cb=lambda filename: False): + return [ match_cb, lambda filename: None, lambda none, buf: 0, lambda none: None, - ) + ] + + def _register_mismatch_callbacks(self, match_cb=lambda filename: False): + xmlsec.register_callbacks(*self._mismatch_callbacks(match_cb)) def _register_match_callbacks(self): xmlsec.register_callbacks( @@ -147,3 +150,9 @@ def mismatch_cb(filename): self._register_mismatch_callbacks(mismatch_cb) self._expect_sign_failure() self.assertEqual(mismatch_calls, 2) + + def test_register_non_callables(self): + for idx in range(4): + cbs = self._mismatch_callbacks() + cbs[idx] = None + self.assertRaises(TypeError, xmlsec.register_callbacks, *cbs) From fc565ba2b82439a12e7bed23103f222bde860b6e Mon Sep 17 00:00:00 2001 From: Oleg Hoefling Date: Sun, 5 Sep 2021 18:20:13 +0200 Subject: [PATCH 222/378] coverage increase: test for graceful failing on read callback wrong return type Signed-off-by: Oleg Hoefling --- tests/test_main.py | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tests/test_main.py b/tests/test_main.py index 648aa5b0..69e8a26d 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -156,3 +156,12 @@ def test_register_non_callables(self): cbs = self._mismatch_callbacks() cbs[idx] = None self.assertRaises(TypeError, xmlsec.register_callbacks, *cbs) + + def test_sign_external_data_fails_on_read_callback_wrong_returns(self): + xmlsec.register_callbacks( + lambda filename: filename == b'cid:123456', + lambda filename: BytesIO(b''), + lambda bio, buf: None, + lambda bio: bio.close(), + ) + self._expect_sign_failure() From f18946b1c9ffd1d030b435dd8f40f85d842e5a5c Mon Sep 17 00:00:00 2001 From: Oleg Hoefling Date: Sun, 5 Sep 2021 18:31:59 +0200 Subject: [PATCH 223/378] skip test failing on windows for now Signed-off-by: Oleg Hoefling --- tests/test_main.py | 27 ++++++++++----------------- 1 file changed, 10 insertions(+), 17 deletions(-) diff --git a/tests/test_main.py b/tests/test_main.py index 69e8a26d..9fb71eaf 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -1,9 +1,10 @@ -import xmlsec -from xmlsec import constants as consts - +import sys from io import BytesIO +from unittest import skipIf +import xmlsec from tests import base +from xmlsec import constants as consts class TestBase64LineSize(base.TestMemoryLeaks): @@ -43,18 +44,11 @@ def setUp(self): def _sign_doc(self): root = self.load_xml("doc.xml") - sign = xmlsec.template.create( - root, - c14n_method=consts.TransformExclC14N, - sign_method=consts.TransformRsaSha1 - ) - xmlsec.template.add_reference( - sign, consts.TransformSha1, uri="cid:123456") + sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) + xmlsec.template.add_reference(sign, consts.TransformSha1, uri="cid:123456") ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file( - self.path("rsakey.pem"), format=consts.KeyDataFormatPem - ) + ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) ctx.sign(sign) return sign @@ -87,16 +81,14 @@ def _find(self, elem, *tags): './' + '/'.join('xmldsig:{}'.format(tag) for tag in tags), namespaces={ 'xmldsig': 'http://www.w3.org/2000/09/xmldsig#', - } + }, )[0] except IndexError as e: raise KeyError(tags) from e def _verify_external_data_signature(self): signature = self._sign_doc() - digest = self._find( - signature, 'SignedInfo', 'Reference', 'DigestValue' - ).text + digest = self._find(signature, 'SignedInfo', 'Reference', 'DigestValue').text self.assertEqual(digest, 'VihZwVMGJ48NsNl7ertVHiURXk8=') def test_sign_external_data_no_callbacks_fails(self): @@ -133,6 +125,7 @@ def match_cb(filename): self._verify_external_data_signature() self.assertEqual(bad_match_calls, 0) + @skipIf(sys.platform == "win32", "unclear behaviour on windows") def test_failed_sign_because_default_callbacks(self): mismatch_calls = 0 From cf38b52c81d80897500f153ae5b9307439d6145a Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 13 Dec 2021 10:31:24 +0000 Subject: [PATCH 224/378] exclude lxml 4.7 because the wheels are missing the lxml includes see https://bugs.launchpad.net/lxml/+bug/1954644 --- pyproject.toml | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 6c69db80..9262cbf5 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -23,4 +23,4 @@ known_first_party = ['xmlsec'] known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] [build-system] -requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4'] +requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] diff --git a/requirements.txt b/requirements.txt index 827d75e0..20a5dfb7 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1,2 @@ pkgconfig -lxml >= 3.8.0 +lxml >= 3.8.0, !=4.7.0 From 9acc1538e3ed7522ab9237ea40ef4abc15d15445 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 13 Dec 2021 11:19:26 +0000 Subject: [PATCH 225/378] remove pkgconfig as it's only a build-system requirement --- requirements.txt | 1 - 1 file changed, 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 20a5dfb7..014bfe10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,2 +1 @@ -pkgconfig lxml >= 3.8.0, !=4.7.0 From 154c51df4769d35a51cb2ac48c5f606772d42df8 Mon Sep 17 00:00:00 2001 From: Thomas Grainger Date: Mon, 13 Dec 2021 11:22:58 +0000 Subject: [PATCH 226/378] use build to build wheels --- .github/workflows/linuxbrew.yml | 4 ++-- .github/workflows/macosx.yml | 4 ++-- .github/workflows/manylinux2010.yml | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 6502b830..0d85caee 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -18,11 +18,11 @@ jobs: echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile brew update brew install python gcc libxml2 libxmlsec1 pkg-config - pip3 install --upgrade setuptools wheel + pip3 install --upgrade setuptools wheel build ln -s $(brew --prefix)/bin/gcc-11 $(brew --prefix)/bin/gcc-5 - name: Build linux_x86_64 wheel run: | - python3 setup.py bdist_wheel + python3 -m build rm -rf build/ - name: Install test dependencies run: | diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 70e00291..b5921dc5 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -14,7 +14,7 @@ jobs: python-version: ${{ matrix.python }} - name: Install build dependencies run: | - pip install --upgrade pip setuptools wheel + pip install --upgrade pip setuptools wheel build brew install libxml2 libxmlsec1 pkg-config - name: Build macosx_x86_64 wheel env: @@ -22,7 +22,7 @@ jobs: CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" run: | - python setup.py bdist_wheel + python -m build rm -rf build/ - name: Set environment variables shell: bash diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index e2b1f449..c357db52 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -11,7 +11,7 @@ jobs: - uses: actions/checkout@v1 - name: Install build dependencies run: | - /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel + /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build - name: Set environment variables shell: bash run: | @@ -22,7 +22,7 @@ jobs: # disable libxml2-2.9.12 because of https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 PYXMLSEC_LIBXML2_VERSION: 2.9.10 run: | - /opt/python/${{ matrix.python-abi }}/bin/python setup.py bdist_wheel + /opt/python/${{ matrix.python-abi }}/bin/python -m build - name: Label manylinux2010_x86_64 wheel run: | ls -la dist/ From a65be810213327343c197384a2cb648654ab3d6d Mon Sep 17 00:00:00 2001 From: Alexander Shadchin Date: Thu, 10 Feb 2022 19:22:38 +0300 Subject: [PATCH 227/378] Switch on modern headers lxml --- src/lxml.c | 2 +- src/lxml.h | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index 862ee682..aa1abae0 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -11,7 +11,7 @@ #include "lxml.h" #include -#include +#include #include #include diff --git a/src/lxml.h b/src/lxml.h index 435ccdff..6824076b 100644 --- a/src/lxml.h +++ b/src/lxml.h @@ -16,7 +16,7 @@ #include #include -#include +#include typedef struct LxmlElement* PyXmlSec_LxmlElementPtr; typedef struct LxmlDocument* PyXmlSec_LxmlDocumentPtr; From bf6984a555f02580dd40f865997c0d9b61d81fa6 Mon Sep 17 00:00:00 2001 From: AbdealiJK Date: Tue, 22 Mar 2022 16:39:39 +0530 Subject: [PATCH 228/378] setup.py: Fix typo in PYXMLSEC_LIBXSLT_VERSION --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 541eb029..45d8e664 100644 --- a/setup.py +++ b/setup.py @@ -168,7 +168,7 @@ def prepare_static_build_linux(self): self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1g') self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION', '1.16') self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', None) - self.libxslt_version = os.environ.get('PYXMLSEC_LIBXLST_VERSION', None) + self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION', None) self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.2.11') self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.2.31') From 5c6bbdb86338ed7ece3cfec017295953a1527b36 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 12:38:37 +0200 Subject: [PATCH 229/378] renew sources for source dists Signed-off-by: oleg.hoefling --- setup.py | 155 +++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 122 insertions(+), 33 deletions(-) diff --git a/setup.py b/setup.py index 45d8e664..9dbf069d 100644 --- a/setup.py +++ b/setup.py @@ -1,20 +1,94 @@ +import contextlib +import html.parser import io +import json import multiprocessing import os +import re import subprocess import sys import tarfile import zipfile from distutils import log +from distutils.version import StrictVersion as Version from distutils.errors import DistutilsError from pathlib import Path -from urllib.request import urlcleanup, urljoin, urlretrieve +from urllib.request import urlcleanup, urljoin, urlopen, urlretrieve from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig -class build_ext(build_ext_orig, object): +class HrefCollector(html.parser.HTMLParser): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.hrefs = [] + + def handle_starttag(self, tag, attrs): + if tag == 'a': + for name, value in attrs: + if name == 'href': + self.hrefs.append(value) + + +def latest_release_from_html(url, matcher): + with contextlib.closing(urlopen(url)) as r: + charset = r.headers.get_content_charset() or 'utf-8' + content = r.read().decode(charset) + collector = HrefCollector() + collector.feed(content) + hrefs = collector.hrefs + + def comp(text): + try: + return Version(matcher.match(text).groupdict()['version']) + except (AttributeError, ValueError): + return Version('0.0') + + latest = max(hrefs, key=comp) + return '{}/{}'.format(url, latest) + + +def latest_release_from_gnome_org_cache(url, lib_name): + cache_url = '{}/cache.json'.format(url) + with contextlib.closing(urlopen(cache_url)) as r: + cache = json.load(r) + latest_version = cache[2][lib_name][-1] + latest_source = cache[1][lib_name][latest_version]['tar.xz'] + return '{}/{}'.format(url, latest_source) + + +def latest_zlib_release(): + return latest_release_from_html( + 'https://zlib.net/fossils', re.compile('zlib-(?P.*).tar.gz') + ) + + +def latest_libiconv_release(): + return latest_release_from_html( + 'https://ftp.gnu.org/pub/gnu/libiconv', re.compile('libiconv-(?P.*).tar.gz') + ) + + +def latest_libxml2_release(): + return latest_release_from_gnome_org_cache( + 'https://download.gnome.org/sources/libxml2', 'libxml2' + ) + + +def latest_libxslt_release(): + return latest_release_from_gnome_org_cache( + 'https://download.gnome.org/sources/libxslt', 'libxslt' + ) + + +def latest_xmlsec_release(): + return latest_release_from_html( + 'https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz') + ) + + +class build_ext(build_ext_orig): def info(self, message): self.announce(message, level=log.INFO) @@ -36,6 +110,7 @@ def run(self): self.libs_dir = Path(os.environ.get('PYXMLSEC_LIBS_DIR', 'libs')) self.libs_dir.mkdir(exist_ok=True) + self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) if sys.platform == 'win32': self.prepare_static_build_win() @@ -165,71 +240,85 @@ def prepare_static_build_win(self): ext.include_dirs = [str(p.absolute()) for p in includes] def prepare_static_build_linux(self): - self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1g') - self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION', '1.16') - self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', None) - self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION', None) - self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.2.11') - self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.2.31') - - self.info('Settings:') - self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) - self.info('{:20} {}'.format('zlib version:', self.zlib_version)) - self.info('{:20} {}'.format('libiconv version:', self.libiconv_version)) - self.info('{:20} {}'.format('libxml2 version:', self.libxml2_version or 'unset, using latest')) - self.info('{:20} {}'.format('libxslt version:', self.libxslt_version or 'unset, using latest')) - self.info('{:20} {}'.format('xmlsec1 version:', self.xmlsec1_version)) + self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1q') + self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION') + self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION') + self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION') + self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION') + self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION') # fetch openssl openssl_tar = next(self.libs_dir.glob('openssl*.tar.gz'), None) if openssl_tar is None: - self.info('OpenSSL source tar not found, downloading ...') + self.info('{:10}: {}'.format('OpenSSL', 'source tar not found, downloading ...')) openssl_tar = self.libs_dir / 'openssl.tar.gz' + self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), str(openssl_tar)) # fetch zlib zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) if zlib_tar is None: - self.info('zlib source tar not found, downloading ...') + self.info('{:10}: {}'.format('zlib', 'source not found, downloading ...')) zlib_tar = self.libs_dir / 'zlib.tar.gz' - urlretrieve('https://zlib.net/zlib-{}.tar.gz'.format(self.zlib_version), str(zlib_tar)) + if self.zlib_version is None: + url = latest_zlib_release() + self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION unset, downloading latest from {}'.format(url))) + else: + url = 'https://zlib.net/fossils/zlib-{}.tar.gz'.format(self.zlib_version) + self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION={}, downloading from {}'.format(self.zlib_version, url))) + urlretrieve(url, str(zlib_tar)) # fetch libiconv libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) if libiconv_tar is None: - self.info('libiconv source tar not found, downloading ...') + self.info('{:10}: {}'.format('libiconv', 'source not found, downloading ...')) libiconv_tar = self.libs_dir / 'libiconv.tar.gz' - urlretrieve( - 'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version), str(libiconv_tar) - ) + if self.libiconv_version is None: + url = latest_libiconv_release() + self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {}'.format(url))) + else: + url = 'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version) + self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_LIBICONV_VERSION={}, downloading from {}'.format(self.libiconv_version, url))) + urlretrieve(url, str(libiconv_tar)) # fetch libxml2 - libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.gz'), None) + libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.xz'), None) if libxml2_tar is None: - self.info('Libxml2 source tar not found, downloading ...') + self.info('{:10}: {}'.format('libxml2', 'source tar not found, downloading ...')) if self.libxml2_version is None: - url = 'http://xmlsoft.org/sources/LATEST_LIBXML2' + url = latest_libxml2_release() + self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {}'.format(url))) else: - url = 'http://xmlsoft.org/sources/libxml2-{}.tar.gz'.format(self.libxml2_version) - libxml2_tar = self.libs_dir / 'libxml2.tar.gz' + version_prefix, _ = self.libxml2_version.split('.', -1) + url = 'https://download.gnome.org/sources/libxml2/{}/libxml2-{}.tar.xz'.format(version_prefix, self.libxml2_version) + self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION={}, downloading from {}'.format(self.libxml2_version, url))) + libxml2_tar = self.libs_dir / 'libxml2.tar.xz' urlretrieve(url, str(libxml2_tar)) # fetch libxslt libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) if libxslt_tar is None: - self.info('libxslt source tar not found, downloading ...') + self.info('{:10}: {}'.format('libxslt', 'source tar not found, downloading ...')) if self.libxslt_version is None: - url = 'http://xmlsoft.org/sources/LATEST_LIBXSLT' + url = latest_libxslt_release() + self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {}'.format(url))) else: - url = 'http://xmlsoft.org/sources/libxslt-{}.tar.gz'.format(self.libxslt_version) + version_prefix, _ = self.libxslt_version.split('.', -1) + url = 'https://download.gnome.org/sources/libxslt/{}/libxslt-{}.tar.xz'.format(version_prefix, self.libxslt_version) + self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION={}, downloading from {}'.format(self.libxslt_version, url))) libxslt_tar = self.libs_dir / 'libxslt.tar.gz' urlretrieve(url, str(libxslt_tar)) # fetch xmlsec1 xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) if xmlsec1_tar is None: - self.info('xmlsec1 source tar not found, downloading ...') - url = 'http://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + self.info('{:10}: {}'.format('xmlsec1', 'source tar not found, downloading ...')) + if self.xmlsec1_version is None: + url = latest_xmlsec_release() + self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {}'.format(url))) + else: + url = 'https://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url))) xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' urlretrieve(url, str(xmlsec1_tar)) From 811c5cca2522283e96773cc78de3736049b5b020 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 12:40:30 +0200 Subject: [PATCH 230/378] remove libxml2 pin in manylinux2010, sdist jobs Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 2 -- .github/workflows/sdist.yml | 2 -- 2 files changed, 4 deletions(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index c357db52..99a81a96 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -19,8 +19,6 @@ jobs: - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true - # disable libxml2-2.9.12 because of https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 - PYXMLSEC_LIBXML2_VERSION: 2.9.10 run: | /opt/python/${{ matrix.python-abi }}/bin/python -m build - name: Label manylinux2010_x86_64 wheel diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index d6cf6c9d..5b5dac96 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -18,8 +18,6 @@ jobs: - name: Install test dependencies env: PYXMLSEC_STATIC_DEPS: true - # disable libxml2-2.9.12 because of https://gitlab.gnome.org/GNOME/libxslt/-/issues/52 - PYXMLSEC_LIBXML2_VERSION: 2.9.10 run: | pip install --upgrade -r requirements-test.txt pip install dist/xmlsec-$(python setup.py --version).tar.gz From 1858a467b5d7ea4ca95d15717b339e492380c134 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 13:05:28 +0200 Subject: [PATCH 231/378] bump github actions versions Signed-off-by: oleg.hoefling --- .github/workflows/linuxbrew.yml | 4 ++-- .github/workflows/macosx.yml | 4 ++-- .github/workflows/manylinux2010.yml | 2 +- .github/workflows/sdist.yml | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 0d85caee..4d2f5ba4 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -4,9 +4,9 @@ jobs: linuxbrew: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install build dependencies diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index b5921dc5..ef72fb78 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -7,9 +7,9 @@ jobs: matrix: python: [3.5, 3.6, 3.7, 3.8, 3.9] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Setup Python - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} - name: Install build dependencies diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 99a81a96..49059d84 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -8,7 +8,7 @@ jobs: matrix: python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Install build dependencies run: | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 5b5dac96..6082fcd6 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -4,9 +4,9 @@ jobs: sdist: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v1 + - uses: actions/checkout@v3 - name: Set up Python 3.9 - uses: actions/setup-python@v2 + uses: actions/setup-python@v4 with: python-version: 3.9 - name: Install build dependencies From 8393c7a967b68ed34f4921d33e4d5f77cb40a803 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 13:10:24 +0200 Subject: [PATCH 232/378] workaround for https://github.com/actions/runner/issues/2033 Signed-off-by: oleg.hoefling --- .github/workflows/manylinux2010.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux2010.yml index 49059d84..d1769b74 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux2010.yml @@ -8,9 +8,11 @@ jobs: matrix: python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v1 - name: Install build dependencies run: | + # https://github.com/actions/runner/issues/2033 + chown -R $(id -u):$(id -g) $PWD /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build - name: Set environment variables shell: bash From 8551a4f425bed5c24c26fd0c4e03a42ecd2d2b4c Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 13:27:42 +0200 Subject: [PATCH 233/378] bump gcc-5 symlink in linuxbrew job Signed-off-by: oleg.hoefling --- .github/workflows/linuxbrew.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 4d2f5ba4..191e2001 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -19,7 +19,8 @@ jobs: brew update brew install python gcc libxml2 libxmlsec1 pkg-config pip3 install --upgrade setuptools wheel build - ln -s $(brew --prefix)/bin/gcc-11 $(brew --prefix)/bin/gcc-5 + ln -s $(brew --prefix)/bin/gcc-12 $(brew --prefix)/bin/gcc-5 + ls -l $(brew --prefix)/bin/gcc* - name: Build linux_x86_64 wheel run: | python3 -m build From 3ebbed8f0cc46c17f13c2e9a6ad98888c3e406c6 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 13:32:26 +0200 Subject: [PATCH 234/378] bump python 3.9 to latest patch in appveyor ci Signed-off-by: oleg.hoefling --- .appveyor.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 54bd2b1e..9155acc0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -9,9 +9,9 @@ environment: - python: 38 - python: 38-x64 - python: 39 - python_version: 3.9.0 + python_version: 3.9.13 - python: 39-x64 - python_version: 3.9.0 + python_version: 3.9.13 install: - ps: | From bc30efd49dab62a9c96f44f0dc31a4de4181dabd Mon Sep 17 00:00:00 2001 From: Chris MacNaughton Date: Fri, 6 May 2022 14:52:01 +0200 Subject: [PATCH 235/378] Resolve key loading issue on big-endian systems. Closes: #208 --- src/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.c b/src/keys.c index 46dbf651..1362b128 100644 --- a/src/keys.c +++ b/src/keys.c @@ -142,7 +142,7 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* Py_ssize_t data_size = 0; PYXMLSEC_DEBUG("load key from file - start"); - if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OH|z:from_file", kwlist, &file, &format, &password)) { + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "OI|z:from_file", kwlist, &file, &format, &password)) { goto ON_FAIL; } From b04a76285188e886e61bbb6540466fc3b5738e39 Mon Sep 17 00:00:00 2001 From: Stanislav Levin Date: Mon, 28 Mar 2022 11:59:00 +0200 Subject: [PATCH 236/378] xmlsec workaround for gh#mehcode/python-xmlsec#84 Fixes #96 --- tests/base.py | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/tests/base.py b/tests/base.py index e834f080..b6b3b56a 100644 --- a/tests/base.py +++ b/tests/base.py @@ -99,10 +99,11 @@ def load(self, name): def load_xml(self, name, xpath=None): """returns xml.etree""" - root = etree.parse(self.path(name)).getroot() - if xpath is None: - return root - return root.find(xpath) + with open(self.path(name)) as f: + root = etree.parse(f).getroot() + if xpath is None: + return root + return root.find(xpath) def dump(self, root): print(etree.tostring(root)) From ceaea9c9ad27bcb82d9b1a30cea83d96d34e2639 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 14:52:19 +0200 Subject: [PATCH 237/378] regenerate stubs, amend according to flake8-pyi, ensure stub generation test is running in the CI Signed-off-by: oleg.hoefling --- .appveyor.yml | 1 + .github/workflows/sdist.yml | 1 + pyproject.toml | 2 +- setup.cfg | 3 + src/xmlsec/__init__.pyi | 57 +++----- src/xmlsec/constants.pyi | 270 +++++++++++++++++------------------- src/xmlsec/template.pyi | 29 ++-- src/xmlsec/tree.pyi | 15 +- tests/test_type_stubs.py | 19 +-- 9 files changed, 188 insertions(+), 209 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index 9155acc0..f7b9e16d 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -44,6 +44,7 @@ build_script: test: off test_script: - pip install -r requirements-test.txt + - pip install black # for stub generation tests - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - pytest -v --color=yes --junitxml=unittests.xml - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 6082fcd6..28fe79fe 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -20,6 +20,7 @@ jobs: PYXMLSEC_STATIC_DEPS: true run: | pip install --upgrade -r requirements-test.txt + pip install black # for stub generation tests pip install dist/xmlsec-$(python setup.py --version).tar.gz - name: Run tests run: | diff --git a/pyproject.toml b/pyproject.toml index 9262cbf5..2bfc3d21 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.black] line_length = 130 skip-string-normalization = true -target_version = ['py38'] +target_version = ['py39'] include = '\.pyi?$' exclude = ''' diff --git a/setup.cfg b/setup.cfg index c61fd65b..88d815b0 100644 --- a/setup.cfg +++ b/setup.cfg @@ -16,4 +16,7 @@ all_files = 1 upload_dir = doc/build/html [flake8] +per-file-ignores = + *.pyi: E301, E302, E305, E501, E701, F401, F822 +exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv* max-line-length = 130 diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 93ff8658..43959222 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,27 +1,12 @@ -import sys -from typing import ( - Any, AnyStr, Callable, IO, Iterable, Optional, Type, TypeVar, Union, - overload) +from collections.abc import Callable, Iterable +from typing import Any, AnyStr, IO, typeVar, overload +from _typeshed import GenericPath, Self, StrOrBytesPath from lxml.etree import _Element -from xmlsec import constants, template, tree from xmlsec.constants import __KeyData as KeyData, __Transform as Transform -if sys.version_info >= (3, 6): - from os import PathLike - from pathlib import PurePath - - _Path = Union[str, bytes, PurePath, PathLike[str], PathLike[bytes]] -elif sys.version_info >= (3, 4): - from pathlib import PurePath - - _Path = Union[str, bytes, PurePath] -else: - _Path = Union[str, bytes] - -_E = TypeVar('_E', bound=_Element) -_K = TypeVar('_K', bound=Key) +_E = typeVar('_E', bound=_Element) def enable_debug_trace(enabled: bool = ...) -> None: ... def init() -> None: ... @@ -29,10 +14,10 @@ def shutdown() -> None: ... def cleanup_callbacks() -> None: ... def register_default_callbacks() -> None: ... def register_callbacks( - input_match_callback: Callable[[bytes], bool], - input_open_callback: Callable[[bytes], Any], - input_read_callback: Callable[[Any, memoryview], int], - input_close_callback: Callable[[Any], None], + input_match_callback: Callable[[bytes], bool], + input_open_callback: Callable[[bytes], Any], + input_read_callback: Callable[[Any, memoryview], int], + input_close_callback: Callable[[Any], None], ) -> None: ... @overload def base64_default_line_size() -> int: ... @@ -40,8 +25,8 @@ def base64_default_line_size() -> int: ... def base64_default_line_size(size: int) -> None: ... class EncryptionContext: - key: Optional[Key] - def __init__(self, manager: Optional[KeysManager] = None) -> None: ... + key: Key | None + def __init__(self, manager: KeysManager | None = ...) -> None: ... def decrypt(self, node: _Element) -> _Element: ... def encrypt_binary(self, template: _E, data: bytes) -> _E: ... def encrypt_uri(self, template: _E, uri: str) -> _E: ... @@ -54,30 +39,30 @@ class InternalError(Error): ... class Key: name: str @classmethod - def from_binary_data(cls: Type[_K], klass: KeyData, data: AnyStr) -> _K: ... + def from_binary_data(cls: type[Self], klass: KeyData, data: AnyStr) -> Self: ... @classmethod - def from_binary_file(cls: Type[_K], klass: KeyData, filename: _Path) -> _K: ... + def from_binary_file(cls: type[Self], klass: KeyData, filename: StrOrBytesPath) -> Self: ... @classmethod - def from_file(cls: Type[_K], file: Union[_Path, IO[AnyStr]], format: int, password: Optional[str] = ...) -> _K: ... + def from_file(cls: type[Self], file: GenericPath | IO[AnyStr], format: int, password: str | None = ...) -> Self: ... @classmethod - def from_memory(cls: Type[_K], data: AnyStr, format: int, password: Optional[str] = ...) -> _K: ... + def from_memory(cls: type[Self], data: AnyStr, format: int, password: str | None = ...) -> Self: ... @classmethod - def generate(cls: Type[_K], klass: KeyData, size: int, type: int) -> _K: ... - def load_cert_from_file(self, file: Union[_Path, IO[AnyStr]], format: int) -> None: ... + def generate(cls: type[Self], klass: KeyData, size: int, type: int) -> Self: ... + def load_cert_from_file(self, file: GenericPath | IO[AnyStr], format: int) -> None: ... def load_cert_from_memory(self, data: AnyStr, format: int) -> None: ... - def __copy__(self: _K) -> _K: ... - def __deepcopy__(self: _K) -> _K: ... + def __copy__(self: Self) -> Self: ... + def __deepcopy__(self: Self) -> Self: ... class KeysManager: def add_key(self, key: Key) -> None: ... - def load_cert(self, filename: _Path, format: int, type: int) -> None: ... + def load_cert(self, filename: StrOrBytesPath, format: int, type: int) -> None: ... def load_cert_from_memory(self, data: AnyStr, format: int, type: int) -> None: ... class SignatureContext: - key: Optional[Key] + key: Key | None def enable_reference_transform(self, transform: Transform) -> None: ... def enable_signature_transform(self, transform: Transform) -> None: ... - def register_id(self, node: _Element, id_attr: str = "ID", id_ns: Optional[str] = None) -> None: ... + def register_id(self, node: _Element, id_attr: str = ..., id_ns: str | None = ...) -> None: ... def set_enabled_key_data(self, keydata_list: Iterable[KeyData]) -> None: ... def sign(self, node: _Element) -> None: ... def sign_binary(self, bytes: bytes, transform: Transform) -> bytes: ... diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 97e00544..8e2165d8 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -1,5 +1,5 @@ import sys -from typing import NamedTuple, Optional +from typing import NamedTuple if sys.version_info >= (3, 8): from typing import Final @@ -7,147 +7,139 @@ else: from typing_extensions import Final class __KeyData(NamedTuple): # __KeyData type + href: str | None name: str - href: Optional[str] class __Transform(NamedTuple): # __Transform type + href: str | None name: str - href: Optional[str] usage: int -DSigNs: Final = 'http://www.w3.org/2000/09/xmldsig#' -EncNs: Final = 'http://www.w3.org/2001/04/xmlenc#' -KeyDataAes: Final = __KeyData('aes', 'http://www.aleksey.com/xmlsec/2002#AESKeyValue') -KeyDataDes: Final = __KeyData('des', 'http://www.aleksey.com/xmlsec/2002#DESKeyValue') -KeyDataDsa: Final = __KeyData('dsa', 'http://www.w3.org/2000/09/xmldsig#DSAKeyValue') -KeyDataEcdsa: Final = __KeyData('ecdsa', 'http://scap.nist.gov/specifications/tmsad/#resource-1.0') -KeyDataEncryptedKey: Final = __KeyData('enc-key', 'http://www.w3.org/2001/04/xmlenc#EncryptedKey') -KeyDataFormatBinary: Final = 1 -KeyDataFormatCertDer: Final = 8 -KeyDataFormatCertPem: Final = 7 -KeyDataFormatDer: Final = 3 -KeyDataFormatPem: Final = 2 -KeyDataFormatPkcs12: Final = 6 -KeyDataFormatPkcs8Der: Final = 5 -KeyDataFormatPkcs8Pem: Final = 4 -KeyDataFormatUnknown: Final = 0 -KeyDataHmac: Final = __KeyData('hmac', 'http://www.aleksey.com/xmlsec/2002#HMACKeyValue') -KeyDataName: Final = __KeyData('key-name', None) -KeyDataRawX509Cert: Final = __KeyData('raw-x509-cert', 'http://www.w3.org/2000/09/xmldsig#rawX509Certificate') -KeyDataRetrievalMethod: Final = __KeyData('retrieval-method', None) -KeyDataRsa: Final = __KeyData('rsa', 'http://www.w3.org/2000/09/xmldsig#RSAKeyValue') -KeyDataTypeAny: Final = 65535 -KeyDataTypeNone: Final = 0 -KeyDataTypePermanent: Final = 16 -KeyDataTypePrivate: Final = 2 -KeyDataTypePublic: Final = 1 -KeyDataTypeSession: Final = 8 -KeyDataTypeSymmetric: Final = 4 -KeyDataTypeTrusted: Final = 256 -KeyDataTypeUnknown: Final = 0 -KeyDataValue: Final = __KeyData('key-value', None) -KeyDataX509: Final = __KeyData('x509', 'http://www.w3.org/2000/09/xmldsig#X509Data') -NodeCanonicalizationMethod: Final = 'CanonicalizationMethod' -NodeCipherData: Final = 'CipherData' -NodeCipherReference: Final = 'CipherReference' -NodeCipherValue: Final = 'CipherValue' -NodeDataReference: Final = 'DataReference' -NodeDigestMethod: Final = 'DigestMethod' -NodeDigestValue: Final = 'DigestValue' -NodeEncryptedData: Final = 'EncryptedData' -NodeEncryptedKey: Final = 'EncryptedKey' -NodeEncryptionMethod: Final = 'EncryptionMethod' -NodeEncryptionProperties: Final = 'EncryptionProperties' -NodeEncryptionProperty: Final = 'EncryptionProperty' -NodeKeyInfo: Final = 'KeyInfo' -NodeKeyName: Final = 'KeyName' -NodeKeyReference: Final = 'KeyReference' -NodeKeyValue: Final = 'KeyValue' -NodeManifest: Final = 'Manifest' -NodeObject: Final = 'Object' -NodeReference: Final = 'Reference' -NodeReferenceList: Final = 'ReferenceList' -NodeSignature: Final = 'Signature' -NodeSignatureMethod: Final = 'SignatureMethod' -NodeSignatureProperties: Final = 'SignatureProperties' -NodeSignatureValue: Final = 'SignatureValue' -NodeSignedInfo: Final = 'SignedInfo' -NodeX509Data: Final = 'X509Data' -Ns: Final = 'http://www.aleksey.com/xmlsec/2002' -NsExcC14N: Final = 'http://www.w3.org/2001/10/xml-exc-c14n#' -NsExcC14NWithComments: Final = 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments' -Soap11Ns: Final = 'http://schemas.xmlsoap.org/soap/envelope/' -Soap12Ns: Final = 'http://www.w3.org/2002/06/soap-envelope' -TransformAes128Cbc: Final = __Transform('aes128-cbc', 'http://www.w3.org/2001/04/xmlenc#aes128-cbc', 16) -TransformAes128Gcm: Final = __Transform('aes128-gcm', 'http://www.w3.org/2009/xmlenc11#aes128-gcm', 16) -TransformAes192Cbc: Final = __Transform('aes192-cbc', 'http://www.w3.org/2001/04/xmlenc#aes192-cbc', 16) -TransformAes192Gcm: Final = __Transform('aes192-gcm', 'http://www.w3.org/2009/xmlenc11#aes192-gcm', 16) -TransformAes256Cbc: Final = __Transform('aes256-cbc', 'http://www.w3.org/2001/04/xmlenc#aes256-cbc', 16) -TransformAes256Gcm: Final = __Transform('aes256-gcm', 'http://www.w3.org/2009/xmlenc11#aes256-gcm', 16) -TransformDes3Cbc: Final = __Transform('tripledes-cbc', 'http://www.w3.org/2001/04/xmlenc#tripledes-cbc', 16) -TransformDsaSha1: Final = __Transform('dsa-sha1', 'http://www.w3.org/2000/09/xmldsig#dsa-sha1', 8) -TransformEcdsaSha1: Final = __Transform('ecdsa-sha1', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha1', 8) -TransformEcdsaSha224: Final = __Transform('ecdsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha224', 8) -TransformEcdsaSha256: Final = __Transform('ecdsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha256', 8) -TransformEcdsaSha384: Final = __Transform('ecdsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha384', 8) -TransformEcdsaSha512: Final = __Transform('ecdsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#ecdsa-sha512', 8) -TransformEnveloped: Final = __Transform('enveloped-signature', 'http://www.w3.org/2000/09/xmldsig#enveloped-signature', 1) -TransformExclC14N: Final = __Transform('exc-c14n', 'http://www.w3.org/2001/10/xml-exc-c14n#', 3) -TransformExclC14NWithComments: Final = __Transform( - 'exc-c14n-with-comments', 'http://www.w3.org/2001/10/xml-exc-c14n#WithComments', 3 -) -TransformHmacMd5: Final = __Transform('hmac-md5', 'http://www.w3.org/2001/04/xmldsig-more#hmac-md5', 8) -TransformHmacRipemd160: Final = __Transform('hmac-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#hmac-ripemd160', 8) -TransformHmacSha1: Final = __Transform('hmac-sha1', 'http://www.w3.org/2000/09/xmldsig#hmac-sha1', 8) -TransformHmacSha224: Final = __Transform('hmac-sha224', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha224', 8) -TransformHmacSha256: Final = __Transform('hmac-sha256', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha256', 8) -TransformHmacSha384: Final = __Transform('hmac-sha384', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha384', 8) -TransformHmacSha512: Final = __Transform('hmac-sha512', 'http://www.w3.org/2001/04/xmldsig-more#hmac-sha512', 8) -TransformInclC14N: Final = __Transform('c14n', 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315', 3) -TransformInclC14N11: Final = __Transform('c14n11', 'http://www.w3.org/2006/12/xml-c14n11', 3) -TransformInclC14N11WithComments: Final = __Transform( - 'c14n11-with-comments', 'http://www.w3.org/2006/12/xml-c14n11#WithComments', 3 -) -TransformInclC14NWithComments: Final = __Transform( - 'c14n-with-comments', - 'http://www.w3.org/TR/2001/REC-xml-c14n-20010315#WithComments', - 3, -) -TransformKWAes128: Final = __Transform('kw-aes128', 'http://www.w3.org/2001/04/xmlenc#kw-aes128', 16) -TransformKWAes192: Final = __Transform('kw-aes192', 'http://www.w3.org/2001/04/xmlenc#kw-aes192', 16) -TransformKWAes256: Final = __Transform('kw-aes256', 'http://www.w3.org/2001/04/xmlenc#kw-aes256', 16) -TransformKWDes3: Final = __Transform('kw-tripledes', 'http://www.w3.org/2001/04/xmlenc#kw-tripledes', 16) -TransformMd5: Final = __Transform('md5', 'http://www.w3.org/2001/04/xmldsig-more#md5', 4) -TransformRemoveXmlTagsC14N: Final = __Transform('remove-xml-tags-transform', None, 3) -TransformRipemd160: Final = __Transform('ripemd160', 'http://www.w3.org/2001/04/xmlenc#ripemd160', 4) -TransformRsaMd5: Final = __Transform('rsa-md5', 'http://www.w3.org/2001/04/xmldsig-more#rsa-md5', 8) -TransformRsaOaep: Final = __Transform('rsa-oaep-mgf1p', 'http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', 16) -TransformRsaPkcs1: Final = __Transform('rsa-1_5', 'http://www.w3.org/2001/04/xmlenc#rsa-1_5', 16) -TransformRsaRipemd160: Final = __Transform('rsa-ripemd160', 'http://www.w3.org/2001/04/xmldsig-more#rsa-ripemd160', 8) -TransformRsaSha1: Final = __Transform('rsa-sha1', 'http://www.w3.org/2000/09/xmldsig#rsa-sha1', 8) -TransformRsaSha224: Final = __Transform('rsa-sha224', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha224', 8) -TransformRsaSha256: Final = __Transform('rsa-sha256', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha256', 8) -TransformRsaSha384: Final = __Transform('rsa-sha384', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha384', 8) -TransformRsaSha512: Final = __Transform('rsa-sha512', 'http://www.w3.org/2001/04/xmldsig-more#rsa-sha512', 8) -TransformSha1: Final = __Transform('sha1', 'http://www.w3.org/2000/09/xmldsig#sha1', 4) -TransformSha224: Final = __Transform('sha224', 'http://www.w3.org/2001/04/xmldsig-more#sha224', 4) -TransformSha256: Final = __Transform('sha256', 'http://www.w3.org/2001/04/xmlenc#sha256', 4) -TransformSha384: Final = __Transform('sha384', 'http://www.w3.org/2001/04/xmldsig-more#sha384', 4) -TransformSha512: Final = __Transform('sha512', 'http://www.w3.org/2001/04/xmlenc#sha512', 4) -TransformUsageAny: Final = 65535 -TransformUsageC14NMethod: Final = 2 -TransformUsageDSigTransform: Final = 1 -TransformUsageDigestMethod: Final = 4 -TransformUsageEncryptionMethod: Final = 16 -TransformUsageSignatureMethod: Final = 8 -TransformUsageUnknown: Final = 0 -TransformVisa3DHack: Final = __Transform('Visa3DHackTransform', None, 1) -TransformXPath: Final = __Transform('xpath', 'http://www.w3.org/TR/1999/REC-xpath-19991116', 1) -TransformXPath2: Final = __Transform('xpath2', 'http://www.w3.org/2002/06/xmldsig-filter2', 1) -TransformXPointer: Final = __Transform('xpointer', 'http://www.w3.org/2001/04/xmldsig-more/xptr', 1) -TransformXslt: Final = __Transform('xslt', 'http://www.w3.org/TR/1999/REC-xslt-19991116', 1) -TypeEncContent: Final = 'http://www.w3.org/2001/04/xmlenc#Content' -TypeEncElement: Final = 'http://www.w3.org/2001/04/xmlenc#Element' -XPath2Ns: Final = 'http://www.w3.org/2002/06/xmldsig-filter2' -XPathNs: Final = 'http://www.w3.org/TR/1999/REC-xpath-19991116' -XPointerNs: Final = 'http://www.w3.org/2001/04/xmldsig-more/xptr' +DSigNs: Final[str] +EncNs: Final[str] +KeyDataAes: Final[__KeyData] +KeyDataDes: Final[__KeyData] +KeyDataDsa: Final[__KeyData] +KeyDataEcdsa: Final[__KeyData] +KeyDataEncryptedKey: Final[__KeyData] +KeyDataFormatBinary: Final[int] +KeyDataFormatCertDer: Final[int] +KeyDataFormatCertPem: Final[int] +KeyDataFormatDer: Final[int] +KeyDataFormatPem: Final[int] +KeyDataFormatPkcs12: Final[int] +KeyDataFormatPkcs8Der: Final[int] +KeyDataFormatPkcs8Pem: Final[int] +KeyDataFormatUnknown: Final[int] +KeyDataHmac: Final[__KeyData] +KeyDataName: Final[__KeyData] +KeyDataRawX509Cert: Final[__KeyData] +KeyDataRetrievalMethod: Final[__KeyData] +KeyDataRsa: Final[__KeyData] +KeyDataTypeAny: Final[int] +KeyDataTypeNone: Final[int] +KeyDataTypePermanent: Final[int] +KeyDataTypePrivate: Final[int] +KeyDataTypePublic: Final[int] +KeyDataTypeSession: Final[int] +KeyDataTypeSymmetric: Final[int] +KeyDataTypeTrusted: Final[int] +KeyDataTypeUnknown: Final[int] +KeyDataValue: Final[__KeyData] +KeyDataX509: Final[__KeyData] +NodeCanonicalizationMethod: Final[str] +NodeCipherData: Final[str] +NodeCipherReference: Final[str] +NodeCipherValue: Final[str] +NodeDataReference: Final[str] +NodeDigestMethod: Final[str] +NodeDigestValue: Final[str] +NodeEncryptedData: Final[str] +NodeEncryptedKey: Final[str] +NodeEncryptionMethod: Final[str] +NodeEncryptionProperties: Final[str] +NodeEncryptionProperty: Final[str] +NodeKeyInfo: Final[str] +NodeKeyName: Final[str] +NodeKeyReference: Final[str] +NodeKeyValue: Final[str] +NodeManifest: Final[str] +NodeObject: Final[str] +NodeReference: Final[str] +NodeReferenceList: Final[str] +NodeSignature: Final[str] +NodeSignatureMethod: Final[str] +NodeSignatureProperties: Final[str] +NodeSignatureValue: Final[str] +NodeSignedInfo: Final[str] +NodeX509Data: Final[str] +Ns: Final[str] +NsExcC14N: Final[str] +NsExcC14NWithComments: Final[str] +Soap11Ns: Final[str] +Soap12Ns: Final[str] +TransformAes128Cbc: Final[__Transform] +TransformAes128Gcm: Final[__Transform] +TransformAes192Cbc: Final[__Transform] +TransformAes192Gcm: Final[__Transform] +TransformAes256Cbc: Final[__Transform] +TransformAes256Gcm: Final[__Transform] +TransformDes3Cbc: Final[__Transform] +TransformDsaSha1: Final[__Transform] +TransformEcdsaSha1: Final[__Transform] +TransformEcdsaSha224: Final[__Transform] +TransformEcdsaSha256: Final[__Transform] +TransformEcdsaSha384: Final[__Transform] +TransformEcdsaSha512: Final[__Transform] +TransformEnveloped: Final[__Transform] +TransformExclC14N: Final[__Transform] +TransformExclC14NWithComments: Final[__Transform] +TransformHmacMd5: Final[__Transform] +TransformHmacRipemd160: Final[__Transform] +TransformHmacSha1: Final[__Transform] +TransformHmacSha224: Final[__Transform] +TransformHmacSha256: Final[__Transform] +TransformHmacSha384: Final[__Transform] +TransformHmacSha512: Final[__Transform] +TransformInclC14N: Final[__Transform] +TransformInclC14N11: Final[__Transform] +TransformInclC14N11WithComments: Final[__Transform] +TransformInclC14NWithComments: Final[__Transform] +TransformKWAes128: Final[__Transform] +TransformKWAes192: Final[__Transform] +TransformKWAes256: Final[__Transform] +TransformKWDes3: Final[__Transform] +TransformMd5: Final[__Transform] +TransformRemoveXmlTagsC14N: Final[__Transform] +TransformRipemd160: Final[__Transform] +TransformRsaMd5: Final[__Transform] +TransformRsaOaep: Final[__Transform] +TransformRsaPkcs1: Final[__Transform] +TransformRsaRipemd160: Final[__Transform] +TransformRsaSha1: Final[__Transform] +TransformRsaSha224: Final[__Transform] +TransformRsaSha256: Final[__Transform] +TransformRsaSha384: Final[__Transform] +TransformRsaSha512: Final[__Transform] +TransformSha1: Final[__Transform] +TransformSha224: Final[__Transform] +TransformSha256: Final[__Transform] +TransformSha384: Final[__Transform] +TransformSha512: Final[__Transform] +TransformUsageAny: Final[int] +TransformUsageC14NMethod: Final[int] +TransformUsageDSigTransform: Final[int] +TransformUsageDigestMethod: Final[int] +TransformUsageEncryptionMethod: Final[int] +TransformUsageSignatureMethod: Final[int] +TransformUsageUnknown: Final[int] +TransformVisa3DHack: Final[__Transform] +TransformXPath: Final[__Transform] +TransformXPath2: Final[__Transform] +TransformXPointer: Final[__Transform] +TransformXslt: Final[__Transform] +TypeEncContent: Final[str] +TypeEncElement: Final[str] +XPath2Ns: Final[str] +XPathNs: Final[str] +XPointerNs: Final[str] diff --git a/src/xmlsec/template.pyi b/src/xmlsec/template.pyi index 162fe25d..a5199fc8 100644 --- a/src/xmlsec/template.pyi +++ b/src/xmlsec/template.pyi @@ -1,16 +1,17 @@ -from typing import Any, Optional, Sequence, Union +from collections.abc import Sequence +from typing import Any from lxml.etree import _Element from xmlsec.constants import __Transform as Transform def add_encrypted_key( - node: _Element, method: Transform, id: Optional[str] = None, type: Optional[str] = None, recipient: Optional[str] = None + node: _Element, method: Transform, id: str | None = ..., type: str | None = ..., recipient: str | None = ... ) -> _Element: ... -def add_key_name(node: _Element, name: Optional[str] = ...) -> _Element: ... +def add_key_name(node: _Element, name: str | None = ...) -> _Element: ... def add_key_value(node: _Element) -> _Element: ... def add_reference( - node: _Element, digest_method: Transform, id: Optional[str] = ..., uri: Optional[str] = ..., type: Optional[str] = ... + node: _Element, digest_method: Transform, id: str | None = ..., uri: str | None = ..., type: str | None = ... ) -> _Element: ... def add_transform(node: _Element, transform: Transform) -> Any: ... def add_x509_data(node: _Element) -> _Element: ... @@ -18,20 +19,20 @@ def create(node: _Element, c14n_method: Transform, sign_method: Transform) -> _E def encrypted_data_create( node: _Element, method: Transform, - id: Optional[str] = ..., - type: Optional[str] = ..., - mime_type: Optional[str] = ..., - encoding: Optional[str] = ..., - ns: Optional[str] = ..., + id: str | None = ..., + type: str | None = ..., + mime_type: str | None = ..., + encoding: str | None = ..., + ns: str | None = ..., ) -> _Element: ... def encrypted_data_ensure_cipher_value(node: _Element) -> _Element: ... -def encrypted_data_ensure_key_info(node: _Element, id: Optional[str] = ..., ns: Optional[str] = ...) -> _Element: ... -def ensure_key_info(node: _Element, id: Optional[str] = ...) -> _Element: ... -def transform_add_c14n_inclusive_namespaces(node: _Element, prefixes: Union[str, Sequence[str]]) -> None: ... +def encrypted_data_ensure_key_info(node: _Element, id: str | None = ..., ns: str | None = ...) -> _Element: ... +def ensure_key_info(node: _Element, id: str | None = ...) -> _Element: ... +def transform_add_c14n_inclusive_namespaces(node: _Element, prefixes: str | Sequence[str]) -> None: ... def x509_data_add_certificate(node: _Element) -> _Element: ... def x509_data_add_crl(node: _Element) -> _Element: ... def x509_data_add_issuer_serial(node: _Element) -> _Element: ... def x509_data_add_ski(node: _Element) -> _Element: ... def x509_data_add_subject_name(node: _Element) -> _Element: ... -def x509_issuer_serial_add_issuer_name(node: _Element, name: Optional[str] = ...) -> _Element: ... -def x509_issuer_serial_add_serial_number(node: _Element, serial: Optional[str] = ...) -> _Element: ... +def x509_issuer_serial_add_issuer_name(node: _Element, name: str | None = ...) -> _Element: ... +def x509_issuer_serial_add_serial_number(node: _Element, serial: str | None = ...) -> _Element: ... diff --git a/src/xmlsec/tree.pyi b/src/xmlsec/tree.pyi index 6447fd08..9f96e447 100644 --- a/src/xmlsec/tree.pyi +++ b/src/xmlsec/tree.pyi @@ -1,17 +1,18 @@ -from typing import Optional, overload, Sequence +from collections.abc import Sequence +from typing import overload from lxml.etree import _Element def add_ids(node: _Element, ids: Sequence[str]) -> None: ... @overload -def find_child(parent: _Element, name: str) -> Optional[_Element]: ... +def find_child(parent: _Element, name: str) -> _Element | None: ... @overload -def find_child(parent: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... +def find_child(parent: _Element, name: str, namespace: str = ...) -> _Element | None: ... @overload -def find_node(node: _Element, name: str) -> Optional[_Element]: ... +def find_node(node: _Element, name: str) -> _Element | None: ... @overload -def find_node(node: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... +def find_node(node: _Element, name: str, namespace: str = ...) -> _Element | None: ... @overload -def find_parent(node: _Element, name: str) -> Optional[_Element]: ... +def find_parent(node: _Element, name: str) -> _Element | None: ... @overload -def find_parent(node: _Element, name: str, namespace: str = ...) -> Optional[_Element]: ... +def find_parent(node: _Element, name: str, namespace: str = ...) -> _Element | None: ... diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py index 3b1c3757..2312c4d9 100644 --- a/tests/test_type_stubs.py +++ b/tests/test_type_stubs.py @@ -1,6 +1,7 @@ """Test type stubs for correctness where possible.""" import os +import pathlib import sys import pytest @@ -10,12 +11,6 @@ black = pytest.importorskip('black') -if sys.version_info >= (3, 4): - from pathlib import Path -else: - from _pytest.pathlib import Path - - constants_stub_header = """ import sys from typing import NamedTuple @@ -27,12 +22,12 @@ class __KeyData(NamedTuple): # __KeyData type - href: str + href: str | None name: str class __Transform(NamedTuple): # __Transform type - href: str + href: str | None name: str usage: int @@ -51,10 +46,11 @@ def gen_constants_stub(): def process_constant(name): """Generate line in stub file for constant name.""" obj = getattr(xmlsec.constants, name) - return '{name}: Final = {obj!r}'.format(name=name, obj=obj) + return '{name}: Final[{type_name}]'.format(name=name, type_name=type(obj).__name__) names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__'))) lines = [process_constant(name) for name in names] + pathlib.Path('constants_stub_gen.pyi').write_text(constants_stub_header + os.linesep.join(lines)) return constants_stub_header + os.linesep.join(lines) @@ -64,8 +60,7 @@ def test_xmlsec_constants_stub(request): Compare it against the existing stub :file:`xmlsec/constants.pyi`. """ - rootdir = Path(str(request.config.rootdir)) - stub = rootdir / 'src' / 'xmlsec' / 'constants.pyi' - mode = black.FileMode(target_versions=[black.TargetVersion.PY38], line_length=130, is_pyi=True, string_normalization=False) + stub = request.config.rootpath / 'src' / 'xmlsec' / 'constants.pyi' + mode = black.FileMode(target_versions={black.TargetVersion.PY39}, line_length=130, is_pyi=True, string_normalization=False) formatted = black.format_file_contents(gen_constants_stub(), fast=False, mode=mode) assert formatted == stub.read_text() From 7d139b39d1cf6774246c2f5be15684a3a5a69c71 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 14:54:32 +0200 Subject: [PATCH 238/378] fix unwanted replacement with sed Signed-off-by: oleg.hoefling --- src/xmlsec/__init__.pyi | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 43959222..7874fc13 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,12 +1,12 @@ from collections.abc import Callable, Iterable -from typing import Any, AnyStr, IO, typeVar, overload +from typing import Any, AnyStr, IO, TypeVar, overload from _typeshed import GenericPath, Self, StrOrBytesPath from lxml.etree import _Element from xmlsec.constants import __KeyData as KeyData, __Transform as Transform -_E = typeVar('_E', bound=_Element) +_E = TypeVar('_E', bound=_Element) def enable_debug_trace(enabled: bool = ...) -> None: ... def init() -> None: ... From d5f5306470e0008254367b83f4c69c822a68093c Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 14:55:45 +0200 Subject: [PATCH 239/378] drop unused imports in stub generation test Signed-off-by: oleg.hoefling --- tests/test_type_stubs.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py index 2312c4d9..af7d53be 100644 --- a/tests/test_type_stubs.py +++ b/tests/test_type_stubs.py @@ -1,8 +1,6 @@ """Test type stubs for correctness where possible.""" import os -import pathlib -import sys import pytest @@ -50,7 +48,6 @@ def process_constant(name): names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__'))) lines = [process_constant(name) for name in names] - pathlib.Path('constants_stub_gen.pyi').write_text(constants_stub_header + os.linesep.join(lines)) return constants_stub_header + os.linesep.join(lines) From ca566bbfb4941796bb3536fb06654a420178af91 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 15:10:35 +0200 Subject: [PATCH 240/378] mark constants with no href with special type in stubs Signed-off-by: oleg.hoefling --- src/xmlsec/constants.pyi | 23 ++++++++++++++++------- tests/test_type_stubs.py | 17 +++++++++++++---- 2 files changed, 29 insertions(+), 11 deletions(-) diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 8e2165d8..3430a027 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -7,11 +7,20 @@ else: from typing_extensions import Final class __KeyData(NamedTuple): # __KeyData type - href: str | None + href: str + name: str + +class __KeyDataNoHref(NamedTuple): # __KeyData type + href: None name: str class __Transform(NamedTuple): # __Transform type - href: str | None + href: str + name: str + usage: int + +class __TransformNoHref(NamedTuple): # __Transform type + href: None name: str usage: int @@ -32,9 +41,9 @@ KeyDataFormatPkcs8Der: Final[int] KeyDataFormatPkcs8Pem: Final[int] KeyDataFormatUnknown: Final[int] KeyDataHmac: Final[__KeyData] -KeyDataName: Final[__KeyData] +KeyDataName: Final[__KeyDataNoHref] KeyDataRawX509Cert: Final[__KeyData] -KeyDataRetrievalMethod: Final[__KeyData] +KeyDataRetrievalMethod: Final[__KeyDataNoHref] KeyDataRsa: Final[__KeyData] KeyDataTypeAny: Final[int] KeyDataTypeNone: Final[int] @@ -45,7 +54,7 @@ KeyDataTypeSession: Final[int] KeyDataTypeSymmetric: Final[int] KeyDataTypeTrusted: Final[int] KeyDataTypeUnknown: Final[int] -KeyDataValue: Final[__KeyData] +KeyDataValue: Final[__KeyDataNoHref] KeyDataX509: Final[__KeyData] NodeCanonicalizationMethod: Final[str] NodeCipherData: Final[str] @@ -110,7 +119,7 @@ TransformKWAes192: Final[__Transform] TransformKWAes256: Final[__Transform] TransformKWDes3: Final[__Transform] TransformMd5: Final[__Transform] -TransformRemoveXmlTagsC14N: Final[__Transform] +TransformRemoveXmlTagsC14N: Final[__TransformNoHref] TransformRipemd160: Final[__Transform] TransformRsaMd5: Final[__Transform] TransformRsaOaep: Final[__Transform] @@ -133,7 +142,7 @@ TransformUsageDigestMethod: Final[int] TransformUsageEncryptionMethod: Final[int] TransformUsageSignatureMethod: Final[int] TransformUsageUnknown: Final[int] -TransformVisa3DHack: Final[__Transform] +TransformVisa3DHack: Final[__TransformNoHref] TransformXPath: Final[__Transform] TransformXPath2: Final[__Transform] TransformXPointer: Final[__Transform] diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py index af7d53be..9ed8f1e2 100644 --- a/tests/test_type_stubs.py +++ b/tests/test_type_stubs.py @@ -18,17 +18,23 @@ else: from typing_extensions import Final - class __KeyData(NamedTuple): # __KeyData type - href: str | None + href: str name: str +class __KeyDataNoHref(NamedTuple): # __KeyData type + href: None + name: str class __Transform(NamedTuple): # __Transform type - href: str | None + href: str name: str usage: int +class __TransformNoHref(NamedTuple): # __Transform type + href: None + name: str + usage: int """ @@ -44,7 +50,10 @@ def gen_constants_stub(): def process_constant(name): """Generate line in stub file for constant name.""" obj = getattr(xmlsec.constants, name) - return '{name}: Final[{type_name}]'.format(name=name, type_name=type(obj).__name__) + type_name = type(obj).__name__ + if type_name in ('__KeyData', '__Transform') and obj.href is None: + type_name += 'NoHref' + return '{name}: Final[{type_name}]'.format(name=name, type_name=type_name) names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__'))) lines = [process_constant(name) for name in names] From 20be5766fe8100da7a367b38f6878050b29ca068 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 15:15:27 +0200 Subject: [PATCH 241/378] add explicit export for constants module Signed-off-by: oleg.hoefling --- src/xmlsec/__init__.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 7874fc13..90881894 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -4,6 +4,7 @@ from _typeshed import GenericPath, Self, StrOrBytesPath from lxml.etree import _Element +from xmlsec import constants as constants, tree as tree from xmlsec.constants import __KeyData as KeyData, __Transform as Transform _E = TypeVar('_E', bound=_Element) From e8ec653591ac9db340a6223606420e2a2d173754 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 15:21:26 +0200 Subject: [PATCH 242/378] skip stub generation test on windows Signed-off-by: oleg.hoefling --- .appveyor.yml | 1 - 1 file changed, 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index f7b9e16d..9155acc0 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -44,7 +44,6 @@ build_script: test: off test_script: - pip install -r requirements-test.txt - - pip install black # for stub generation tests - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - pytest -v --color=yes --junitxml=unittests.xml - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } From 4062036663b5b516c65c7be179936877a4420500 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 16:29:02 +0200 Subject: [PATCH 243/378] introduce pre-commit Signed-off-by: oleg.hoefling --- .gitignore | 1 + .pre-commit-config.yaml | 48 ++++++++ doc/Makefile | 2 +- doc/source/conf.py | 23 ++-- mypy.ini | 16 --- pyproject.toml | 21 ++++ setup.py | 58 +++++---- src/xmlsec/__init__.pyi | 14 ++- tests/base.py | 29 ++--- tests/data/deskey.bin | 2 +- tests/data/doc.xml | 2 +- tests/data/enc1-in.xml | 2 +- tests/data/enc1-out.xml | 2 +- tests/data/enc2-out.xml | 2 +- tests/data/rsacert.pem | 8 +- tests/data/sign1-in.xml | 5 +- tests/data/sign1-out.xml | 4 +- tests/data/sign2-in.xml | 4 +- tests/data/sign2-out.xml | 4 +- tests/data/sign3-in.xml | 4 +- tests/data/sign3-out.xml | 4 +- tests/data/sign4-in.xml | 4 +- tests/data/sign4-out.xml | 2 +- xmlsec_extra.py | 98 --------------- xmlsec_setupinfo.py | 258 --------------------------------------- 25 files changed, 163 insertions(+), 454 deletions(-) create mode 100644 .pre-commit-config.yaml delete mode 100644 mypy.ini delete mode 100644 xmlsec_extra.py delete mode 100644 xmlsec_setupinfo.py diff --git a/.gitignore b/.gitignore index 669df482..15f47985 100644 --- a/.gitignore +++ b/.gitignore @@ -5,6 +5,7 @@ !.appveyor* !.git* !.readthedocs.yaml +!.pre-commit-config.yaml # Python /dist diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml new file mode 100644 index 00000000..3080b068 --- /dev/null +++ b/.pre-commit-config.yaml @@ -0,0 +1,48 @@ +# See https://pre-commit.com for more information +# See https://pre-commit.com/hooks.html for more hooks +exclude: ".*.diff" # exclude patches +repos: +- repo: https://github.com/psf/black + rev: 22.6.0 + hooks: + - id: black + types: [] + files: ^.*.pyi?$ + exclude: ^doc/ +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v4.3.0 + hooks: + - id: no-commit-to-branch + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-ast + - id: check-merge-conflict + - id: check-json + - id: detect-private-key + - id: mixed-line-ending + - id: pretty-format-json + args: [--autofix] +- repo: https://github.com/PyCQA/flake8 + rev: 5.0.4 + hooks: + - id: flake8 + exclude: ^setup.py$ + additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] +- repo: https://github.com/PyCQA/isort + rev: 5.10.1 + hooks: + - id: isort +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v0.971 + hooks: + - id: mypy + exclude: (setup.py|tests/.*.py|doc/.*) + types: [] + files: ^.*.pyi?$ + additional_dependencies: [lxml-stubs,types-docutils] +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.9.0 + hooks: + - id: rst-backticks diff --git a/doc/Makefile b/doc/Makefile index 119469fb..9b6324b7 100644 --- a/doc/Makefile +++ b/doc/Makefile @@ -17,4 +17,4 @@ help: # Catch-all target: route all unknown targets to Sphinx using the new # "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). %: Makefile - @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) \ No newline at end of file + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/doc/source/conf.py b/doc/source/conf.py index 8e39a5b6..7ff2b1f8 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -4,8 +4,11 @@ import urllib.request import lxml -from docutils.nodes import reference -from packaging.version import parse +from docutils.nodes import Text, reference +from packaging.version import Version, parse +from sphinx.addnodes import pending_xref +from sphinx.application import Sphinx +from sphinx.environment import BuildEnvironment from sphinx.errors import ExtensionError if sys.version_info >= (3, 8): @@ -23,22 +26,22 @@ master_doc = 'index' project = u'python-xmlsec' -copyright = u'2020, Oleg Hoefling ' +copyright = u'2020, Oleg Hoefling ' # noqa: A001 author = u'Bulat Gaifullin ' release = importlib_metadata.version('xmlsec') -parsed = parse(release) +parsed: Version = parse(release) version = '{}.{}'.format(parsed.major, parsed.minor) language = None -exclude_patterns = [] +exclude_patterns: list[str] = [] pygments_style = 'sphinx' todo_include_todos = False html_theme = 'furo' -html_static_path = [] +html_static_path: list[str] = [] htmlhelp_basename = 'python-xmlsecdoc' -latex_elements = {} +latex_elements: dict[str, str] = {} latex_documents = [ ( master_doc, @@ -72,7 +75,7 @@ lxml_element_cls_doc_uri = 'https://lxml.de/api/lxml.etree._Element-class.html' -def lxml_element_doc_reference(app, env, node, contnode): +def lxml_element_doc_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: Text) -> reference: """ Handle a missing reference only if it is a ``lxml.etree._Element`` ref. @@ -83,13 +86,13 @@ def lxml_element_doc_reference(app, env, node, contnode): and node.get('reftarget', None) == 'lxml.etree._Element' and contnode.astext() in ('lxml.etree._Element', '_Element') ): - reftitle = '(in lxml v{})'.format(lxml.__version__) + reftitle = '(in lxml v{})'.format(lxml.__version__) # type: ignore[attr-defined] newnode = reference('', '', internal=False, refuri=lxml_element_cls_doc_uri, reftitle=reftitle) newnode.append(contnode) return newnode -def setup(app): +def setup(app: Sphinx) -> None: # first, check whether the doc URL is still valid if urllib.request.urlopen(lxml_element_cls_doc_uri).getcode() != 200: raise ExtensionError('URL to `lxml.etree._Element` docs is not accesible.') diff --git a/mypy.ini b/mypy.ini deleted file mode 100644 index f404c54c..00000000 --- a/mypy.ini +++ /dev/null @@ -1,16 +0,0 @@ -[mypy] -files = src -ignore_missing_imports = False -warn_unused_configs = True -disallow_subclassing_any = True -disallow_any_generics = True -disallow_untyped_calls = True -disallow_untyped_defs = True -disallow_incomplete_defs = True -check_untyped_defs = True -disallow_untyped_decorators = True -no_implicit_optional = True -warn_redundant_casts = True -warn_unused_ignores = True -warn_return_any = True -no_implicit_reexport = True diff --git a/pyproject.toml b/pyproject.toml index 2bfc3d21..e28878e3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,24 @@ +[tool.mypy] +files = ['src'] +ignore_missing_imports = false +warn_unused_configs = true +disallow_subclassing_any = true +disallow_any_generics = true +disallow_untyped_calls = true +disallow_untyped_defs = true +disallow_incomplete_defs = true +check_untyped_defs = true +disallow_untyped_decorators = true +disallow_any_unimported = true +strict_optional = true +no_implicit_optional = true +warn_redundant_casts = true +warn_unused_ignores = true +warn_return_any = true +warn_no_return = true +no_implicit_reexport = true +show_error_codes = true + [tool.black] line_length = 130 skip-string-normalization = true diff --git a/setup.py b/setup.py index 9dbf069d..da3a0ad4 100644 --- a/setup.py +++ b/setup.py @@ -10,8 +10,8 @@ import tarfile import zipfile from distutils import log -from distutils.version import StrictVersion as Version from distutils.errors import DistutilsError +from distutils.version import StrictVersion as Version from pathlib import Path from urllib.request import urlcleanup, urljoin, urlopen, urlretrieve @@ -59,33 +59,23 @@ def latest_release_from_gnome_org_cache(url, lib_name): def latest_zlib_release(): - return latest_release_from_html( - 'https://zlib.net/fossils', re.compile('zlib-(?P.*).tar.gz') - ) + return latest_release_from_html('https://zlib.net/fossils', re.compile('zlib-(?P.*).tar.gz')) def latest_libiconv_release(): - return latest_release_from_html( - 'https://ftp.gnu.org/pub/gnu/libiconv', re.compile('libiconv-(?P.*).tar.gz') - ) + return latest_release_from_html('https://ftp.gnu.org/pub/gnu/libiconv', re.compile('libiconv-(?P.*).tar.gz')) def latest_libxml2_release(): - return latest_release_from_gnome_org_cache( - 'https://download.gnome.org/sources/libxml2', 'libxml2' - ) + return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxml2', 'libxml2') def latest_libxslt_release(): - return latest_release_from_gnome_org_cache( - 'https://download.gnome.org/sources/libxslt', 'libxslt' - ) + return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxslt', 'libxslt') def latest_xmlsec_release(): - return latest_release_from_html( - 'https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz') - ) + return latest_release_from_html('https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz')) class build_ext(build_ext_orig): @@ -265,7 +255,9 @@ def prepare_static_build_linux(self): self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION unset, downloading latest from {}'.format(url))) else: url = 'https://zlib.net/fossils/zlib-{}.tar.gz'.format(self.zlib_version) - self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION={}, downloading from {}'.format(self.zlib_version, url))) + self.info( + '{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION={}, downloading from {}'.format(self.zlib_version, url)) + ) urlretrieve(url, str(zlib_tar)) # fetch libiconv @@ -278,7 +270,11 @@ def prepare_static_build_linux(self): self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {}'.format(url))) else: url = 'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version) - self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_LIBICONV_VERSION={}, downloading from {}'.format(self.libiconv_version, url))) + self.info( + '{:10}: {}'.format( + 'zlib', 'PYXMLSEC_LIBICONV_VERSION={}, downloading from {}'.format(self.libiconv_version, url) + ) + ) urlretrieve(url, str(libiconv_tar)) # fetch libxml2 @@ -290,8 +286,14 @@ def prepare_static_build_linux(self): self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {}'.format(url))) else: version_prefix, _ = self.libxml2_version.split('.', -1) - url = 'https://download.gnome.org/sources/libxml2/{}/libxml2-{}.tar.xz'.format(version_prefix, self.libxml2_version) - self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION={}, downloading from {}'.format(self.libxml2_version, url))) + url = 'https://download.gnome.org/sources/libxml2/{}/libxml2-{}.tar.xz'.format( + version_prefix, self.libxml2_version + ) + self.info( + '{:10}: {}'.format( + 'libxml2', 'PYXMLSEC_LIBXML2_VERSION={}, downloading from {}'.format(self.libxml2_version, url) + ) + ) libxml2_tar = self.libs_dir / 'libxml2.tar.xz' urlretrieve(url, str(libxml2_tar)) @@ -304,8 +306,14 @@ def prepare_static_build_linux(self): self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {}'.format(url))) else: version_prefix, _ = self.libxslt_version.split('.', -1) - url = 'https://download.gnome.org/sources/libxslt/{}/libxslt-{}.tar.xz'.format(version_prefix, self.libxslt_version) - self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION={}, downloading from {}'.format(self.libxslt_version, url))) + url = 'https://download.gnome.org/sources/libxslt/{}/libxslt-{}.tar.xz'.format( + version_prefix, self.libxslt_version + ) + self.info( + '{:10}: {}'.format( + 'libxslt', 'PYXMLSEC_LIBXSLT_VERSION={}, downloading from {}'.format(self.libxslt_version, url) + ) + ) libxslt_tar = self.libs_dir / 'libxslt.tar.gz' urlretrieve(url, str(libxslt_tar)) @@ -318,7 +326,11 @@ def prepare_static_build_linux(self): self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {}'.format(url))) else: url = 'https://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) - self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url))) + self.info( + '{:10}: {}'.format( + 'xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url) + ) + ) xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' urlretrieve(url, str(xmlsec1_tar)) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 90881894..be0bd659 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -1,11 +1,13 @@ from collections.abc import Callable, Iterable -from typing import Any, AnyStr, IO, TypeVar, overload -from _typeshed import GenericPath, Self, StrOrBytesPath +from typing import IO, Any, AnyStr, TypeVar, overload +from _typeshed import GenericPath, Self, StrOrBytesPath from lxml.etree import _Element -from xmlsec import constants as constants, tree as tree -from xmlsec.constants import __KeyData as KeyData, __Transform as Transform +from xmlsec import constants as constants +from xmlsec import tree as tree +from xmlsec.constants import __KeyData as KeyData +from xmlsec.constants import __Transform as Transform _E = TypeVar('_E', bound=_Element) @@ -44,12 +46,12 @@ class Key: @classmethod def from_binary_file(cls: type[Self], klass: KeyData, filename: StrOrBytesPath) -> Self: ... @classmethod - def from_file(cls: type[Self], file: GenericPath | IO[AnyStr], format: int, password: str | None = ...) -> Self: ... + def from_file(cls: type[Self], file: GenericPath[AnyStr] | IO[AnyStr], format: int, password: str | None = ...) -> Self: ... @classmethod def from_memory(cls: type[Self], data: AnyStr, format: int, password: str | None = ...) -> Self: ... @classmethod def generate(cls: type[Self], klass: KeyData, size: int, type: int) -> Self: ... - def load_cert_from_file(self, file: GenericPath | IO[AnyStr], format: int) -> None: ... + def load_cert_from_file(self, file: GenericPath[AnyStr] | IO[AnyStr], format: int) -> None: ... def load_cert_from_memory(self, data: AnyStr, format: int) -> None: ... def __copy__(self: Self) -> Self: ... def __deepcopy__(self: Self) -> Self: ... diff --git a/tests/base.py b/tests/base.py index b6b3b56a..06acf413 100644 --- a/tests/base.py +++ b/tests/base.py @@ -7,10 +7,6 @@ import xmlsec -if sys.version_info < (3,): - unittest.TestCase.assertRaisesRegex = unittest.TestCase.assertRaisesRegexp - - etype = type(etree.Element("test")) ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs} @@ -22,7 +18,6 @@ def get_memory_usage(): return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss - except ImportError: resource = None @@ -62,7 +57,7 @@ def run(self, result=None): o_count = gc.get_count()[0] m_hits = 0 o_hits = 0 - for i in range(self.iterations): + for _ in range(self.iterations): super(TestMemoryLeaks, self).run(result=result) m_usage_n = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss if m_usage_n > m_usage: @@ -89,16 +84,16 @@ def run(self, result=None): result.addError(self, sys.exc_info()) def path(self, name): - """returns full path for resource""" + """Return full path for resource.""" return os.path.join(self.data_dir, name) def load(self, name): - """loads resource by name""" + """Load resource by name.""" with open(self.path(name), "rb") as stream: return stream.read() def load_xml(self, name, xpath=None): - """returns xml.etree""" + """Return xml.etree.""" with open(self.path(name)) as f: root = etree.parse(f).getroot() if xpath is None: @@ -108,25 +103,25 @@ def load_xml(self, name, xpath=None): def dump(self, root): print(etree.tostring(root)) - def assertXmlEqual(self, first, second, msg=None): - """Checks equality of etree.roots""" + def assertXmlEqual(self, first, second, msg=None): # noqa: N802 + """Check equality of etree.roots.""" msg = msg or '' if first.tag != second.tag: - self.fail('Tags do not match: %s and %s. %s' % (first.tag, second.tag, msg)) + self.fail('Tags do not match: {} and {}. {}'.format(first.tag, second.tag, msg)) for name, value in first.attrib.items(): if second.attrib.get(name) != value: - self.fail('Attributes do not match: %s=%r, %s=%r. %s' % (name, value, name, second.attrib.get(name), msg)) + self.fail('Attributes do not match: {}={!r}, {}={!r}. {}'.format(name, value, name, second.attrib.get(name), msg)) for name in second.attrib.keys(): if name not in first.attrib: - self.fail('x2 has an attribute x1 is missing: %s. %s' % (name, msg)) + self.fail('x2 has an attribute x1 is missing: {}. {}'.format(name, msg)) if not xml_text_compare(first.text, second.text): - self.fail('text: %r != %r. %s' % (first.text, second.text, msg)) + self.fail('text: {!r} != {!r}. {}'.format(first.text, second.text, msg)) if not xml_text_compare(first.tail, second.tail): - self.fail('tail: %r != %r. %s' % (first.tail, second.tail, msg)) + self.fail('tail: {!r} != {!r}. {}'.format(first.tail, second.tail, msg)) cl1 = sorted(first.getchildren(), key=lambda x: x.tag) cl2 = sorted(second.getchildren(), key=lambda x: x.tag) if len(cl1) != len(cl2): - self.fail('children length differs, %i != %i. %s' % (len(cl1), len(cl2), msg)) + self.fail('children length differs, {} != {}. {}'.format(len(cl1), len(cl2), msg)) i = 0 for c1, c2 in zip(cl1, cl2): i += 1 diff --git a/tests/data/deskey.bin b/tests/data/deskey.bin index 019924a7..73245c3c 100644 --- a/tests/data/deskey.bin +++ b/tests/data/deskey.bin @@ -1 +1 @@ -012345670123456701234567 \ No newline at end of file +012345670123456701234567 diff --git a/tests/data/doc.xml b/tests/data/doc.xml index fd474859..39f8d761 100644 --- a/tests/data/doc.xml +++ b/tests/data/doc.xml @@ -4,4 +4,4 @@ XML Security Library example: Original XML doc file for enc example. --> Hello, World! - \ No newline at end of file +
diff --git a/tests/data/enc1-in.xml b/tests/data/enc1-in.xml index fd474859..39f8d761 100644 --- a/tests/data/enc1-in.xml +++ b/tests/data/enc1-in.xml @@ -4,4 +4,4 @@ XML Security Library example: Original XML doc file for enc example. --> Hello, World! - \ No newline at end of file + diff --git a/tests/data/enc1-out.xml b/tests/data/enc1-out.xml index 9499453b..ab0b1a6c 100644 --- a/tests/data/enc1-out.xml +++ b/tests/data/enc1-out.xml @@ -19,4 +19,4 @@ DY/U86tTpTn95NwHD10SLyrL6rpXdbEuoIQHhWLwV9uQxnJA/Pn1KZ+xXK/fePfP 2pb5Mxd0f+AW56Cs3MfQ9HJkUVeliSi1hVCNCVHTKeMyC2VL6lPhQ9+L01aSeTSY - \ No newline at end of file + diff --git a/tests/data/enc2-out.xml b/tests/data/enc2-out.xml index 6556248e..4b3b5c34 100644 --- a/tests/data/enc2-out.xml +++ b/tests/data/enc2-out.xml @@ -19,4 +19,4 @@ CTBwsOXCAEJYXPkTrnB3qQ== 4m5BRKEswOe8JISY7NrPGLBYv7Ay5pBV+nG6it51gz0= - \ No newline at end of file + diff --git a/tests/data/rsacert.pem b/tests/data/rsacert.pem index 02489a43..e8a68228 100644 --- a/tests/data/rsacert.pem +++ b/tests/data/rsacert.pem @@ -32,13 +32,13 @@ Certificate: 65:c3 Exponent: 65537 (0x10001) X509v3 extensions: - X509v3 Basic Constraints: + X509v3 Basic Constraints: CA:FALSE - Netscape Comment: + Netscape Comment: OpenSSL Generated Certificate - X509v3 Subject Key Identifier: + X509v3 Subject Key Identifier: 24:84:2C:F2:D4:59:20:62:8B:2E:5C:86:90:A3:AA:30:BA:27:1A:9C - X509v3 Authority Key Identifier: + X509v3 Authority Key Identifier: keyid:B4:B9:EF:9A:E6:97:0E:68:65:1E:98:CE:FA:55:0D:89:06:DB:4C:7C DirName:/C=US/ST=California/L=Sunnyvale/O=XML Security Library (http://www.aleksey.com/xmlsec)/OU=Root Certificate/CN=Aleksey Sanin/emailAddress=xmlsec@aleksey.com serial:00 diff --git a/tests/data/sign1-in.xml b/tests/data/sign1-in.xml index ac71a949..0a0cd442 100644 --- a/tests/data/sign1-in.xml +++ b/tests/data/sign1-in.xml @@ -1,6 +1,6 @@ - @@ -24,4 +24,3 @@ XML Security Library example: Simple signature template file for sign1 example.
- diff --git a/tests/data/sign1-out.xml b/tests/data/sign1-out.xml index 04d8fed0..f46ac1f4 100644 --- a/tests/data/sign1-out.xml +++ b/tests/data/sign1-out.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign2-in.xml b/tests/data/sign2-in.xml index 5d9fb352..2f2592f2 100644 --- a/tests/data/sign2-in.xml +++ b/tests/data/sign2-in.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign2-out.xml b/tests/data/sign2-out.xml index b37cad94..b5782d6c 100644 --- a/tests/data/sign2-out.xml +++ b/tests/data/sign2-out.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign3-in.xml b/tests/data/sign3-in.xml index f75da16a..96260b8f 100644 --- a/tests/data/sign3-in.xml +++ b/tests/data/sign3-in.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign3-out.xml b/tests/data/sign3-out.xml index 847e1af2..b7bf15c3 100644 --- a/tests/data/sign3-out.xml +++ b/tests/data/sign3-out.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign4-in.xml b/tests/data/sign4-in.xml index cc00479b..d49fc3ae 100644 --- a/tests/data/sign4-in.xml +++ b/tests/data/sign4-in.xml @@ -1,6 +1,6 @@ - diff --git a/tests/data/sign4-out.xml b/tests/data/sign4-out.xml index a6fecb44..bdd1014e 100644 --- a/tests/data/sign4-out.xml +++ b/tests/data/sign4-out.xml @@ -52,4 +52,4 @@ ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL NJ2D
-
\ No newline at end of file + diff --git a/xmlsec_extra.py b/xmlsec_extra.py deleted file mode 100644 index 9bf6c86a..00000000 --- a/xmlsec_extra.py +++ /dev/null @@ -1,98 +0,0 @@ -import os -import sys - -try: - from urlparse import urljoin - from urllib import urlretrieve, urlcleanup -except ImportError: - from urllib.parse import urljoin - from urllib.request import urlretrieve, urlcleanup - - -# use pre-built libraries on Windows -def get_prebuilt_libs(download_dir, static_include_dirs, static_library_dirs): - assert sys.platform.startswith('win') - libs = download_and_extract_windows_binaries(download_dir) - for ln, path in libs.items(): - if ln == 'xmlsec1': - i = os.path.join(path, 'include', 'xmlsec1') - else: - i = os.path.join(path, 'include') - - l = os.path.join(path, 'lib') - assert os.path.exists(i), 'does not exist: %s' % i - assert os.path.exists(l), 'does not exist: %s' % l - static_include_dirs.append(i) - static_library_dirs.append(l) - - -def download_and_extract_windows_binaries(destdir): - url = "https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/" - if sys.version_info < (3, 5): - if sys.maxsize > 2147483647: - suffix = "vs2008.win64" - else: - suffix = "vs2008.win32" - else: - if sys.maxsize > 2147483647: - suffix = "win64" - else: - suffix = "win32" - - libs = { - 'libxml2': 'libxml2-2.9.4.{}.zip'.format(suffix), - 'libxslt': 'libxslt-1.1.29.{}.zip'.format(suffix), - 'zlib': 'zlib-1.2.8.{}.zip'.format(suffix), - 'iconv': 'iconv-1.14.{}.zip'.format(suffix), - 'openssl': 'openssl-1.0.1.{}.zip'.format(suffix), - 'xmlsec': 'xmlsec-1.2.24.{}.zip'.format(suffix), - } - - if not os.path.exists(destdir): - os.makedirs(destdir) - - for ln, fn in libs.items(): - srcfile = urljoin(url, fn) - destfile = os.path.join(destdir, fn) - if os.path.exists(destfile + ".keep"): - print('Using local copy of "{}"'.format(srcfile)) - else: - print('Retrieving "%s" to "%s"' % (srcfile, destfile)) - urlcleanup() # work around FTP bug 27973 in Py2.7.12+ - urlretrieve(srcfile, destfile) - - libs[ln] = unpack_zipfile(destfile, destdir) - - return libs - - -def find_top_dir_of_zipfile(zipfile): - topdir = None - files = [f.filename for f in zipfile.filelist] - dirs = [d for d in files if d.endswith('/')] - if dirs: - dirs.sort(key=len) - topdir = dirs[0] - topdir = topdir[:topdir.index("/")+1] - for path in files: - if not path.startswith(topdir): - topdir = None - break - assert topdir, ( - "cannot determine single top-level directory in zip file %s" % - zipfile.filename) - return topdir.rstrip('/') - - -def unpack_zipfile(zipfn, destdir): - assert zipfn.endswith('.zip') - import zipfile - print('Unpacking %s into %s' % (os.path.basename(zipfn), destdir)) - f = zipfile.ZipFile(zipfn) - try: - extracted_dir = os.path.join(destdir, find_top_dir_of_zipfile(f)) - f.extractall(path=destdir) - finally: - f.close() - assert os.path.exists(extracted_dir), 'missing: %s' % extracted_dir - return extracted_dir diff --git a/xmlsec_setupinfo.py b/xmlsec_setupinfo.py deleted file mode 100644 index bcfbd321..00000000 --- a/xmlsec_setupinfo.py +++ /dev/null @@ -1,258 +0,0 @@ -from __future__ import print_function - -import glob -import os -import pkg_resources -import sys - -from distutils.errors import DistutilsOptionError - - -WIN32 = sys.platform.lower().startswith('win') - -__MODULE_NAME = "xmlsec" -__MODULE_VERSION = None -__MODULE_DESCRIPTION = "Python bindings for the XML Security Library" -__MODULE_REQUIREMENTS = None -__XMLSEC_CONFIG = None - - -def name(): - return __MODULE_NAME - - -def version(): - global __MODULE_VERSION - if __MODULE_VERSION is None: - with open(os.path.join(get_base_dir(), 'version.txt')) as f: - __MODULE_VERSION = f.read().strip() - return __MODULE_VERSION - - -def description(): - return __MODULE_DESCRIPTION - - -def sources(): - return sorted(glob.glob(os.path.join(get_base_dir(), "src", "*.c"))) - - -def define_macros(): - macros = [ - ("MODULE_NAME", __MODULE_NAME), - ("MODULE_VERSION", version()), - ] - if OPTION_ENABLE_DEBUG: - macros.append(("PYXMLSEC_ENABLE_DEBUG", "1")) - - macros.extend(xmlsec_config()['define_macros']) - - return macros - - -def cflags(): - options = [] - if WIN32: - options.append("/Zi") - else: - options.append("-g") - options.append("-std=c99") - options.append("-fno-strict-aliasing") - options.append("-Wno-error=declaration-after-statement") - options.append("-Werror=implicit-function-declaration") - - if OPTION_ENABLE_DEBUG: - options.append("-Wall") - options.append("-O0") - else: - options.append("-Os") - - return options - - -def include_dirs(): - import lxml - - dirs = xmlsec_config()['include_dirs'] - dirs.extend(lxml.get_include()) - return dirs - - -def libraries(): - return xmlsec_config()['libraries'] - - -def library_dirs(): - return xmlsec_config()['library_dirs'] - - -def dev_status(): - _version = version() - if 'a' in _version: - return 'Development Status :: 3 - Alpha' - elif 'b' in _version or 'c' in _version: - return 'Development Status :: 4 - Beta' - else: - return 'Development Status :: 5 - Production/Stable' - - -def requirements(): - global __MODULE_REQUIREMENTS - if __MODULE_REQUIREMENTS is None: - with open(os.path.join(get_base_dir(), "requirements.txt")) as f: - __MODULE_REQUIREMENTS = [str(req) for req in pkg_resources.parse_requirements(f)] - return __MODULE_REQUIREMENTS - - -def xmlsec_config(): - global __XMLSEC_CONFIG - - if __XMLSEC_CONFIG is None: - __XMLSEC_CONFIG = load_xmlsec1_config() - - return __XMLSEC_CONFIG - - -def load_xmlsec1_config(): - config = None - - if WIN32: - import xmlsec_extra - - config = { - 'define_macros': [ - ('XMLSEC_CRYPTO', '\\"openssl\\"'), - ('__XMLSEC_FUNCTION__', '__FUNCTION__'), - ('XMLSEC_NO_GOST', '1'), - ('XMLSEC_NO_XKMS', '1'), - ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), - ('XMLSEC_CRYPTO_OPENSSL', '1'), - ('UNICODE', '1'), - ('_UNICODE', '1'), - ('LIBXML_ICONV_ENABLED', 1), - ('LIBXML_STATIC', '1'), - ('LIBXSLT_STATIC', '1'), - ('XMLSEC_STATIC', '1'), - ('inline', '__inline'), - ], - 'libraries': [ - 'libxmlsec_a', - 'libxmlsec-openssl_a', - 'libeay32', - 'iconv_a', - 'libxslt_a', - 'libexslt_a', - 'libxml2_a', - 'zlib', - 'WS2_32', - 'Advapi32', - 'User32', - 'Gdi32', - 'Crypt32', - ], - 'include_dirs': [], - 'library_dirs': [], - } - - xmlsec_extra.get_prebuilt_libs( - OPTION_DOWNLOAD_DIR, config['include_dirs'], config['library_dirs'] - ) - else: - import pkgconfig - - try: - config = pkgconfig.parse('xmlsec1') - except EnvironmentError: - pass - - if config is None or not config.get('libraries'): - fatal_xmlsec1_error() - - # make sure that all options are list - for x in ('libraries', 'include_dirs', 'library_dirs'): - config[x] = list(config.get(x) or []) - - # fix macros, ensure that macros is list - macros = list(config.get('define_macros', [])) - for i, v in enumerate(macros): - if v[0] == 'XMLSEC_CRYPTO' and not (v[1].startswith('"') and v[1].endswith('"')): - macros[i] = ('XMLSEC_CRYPTO', '"{0}"'.format(v[1])) - break - config['define_macros'] = macros - return config - - -def fatal_xmlsec1_error(): - print('*********************************************************************************') - print('Could not find xmlsec1 config. Are libxmlsec1-dev and pkg-config installed?') - if sys.platform in ('darwin',): - print('Perhaps try: xcode-select --install') - print('*********************************************************************************') - sys.exit(1) - - -def get_base_dir(): - return os.path.abspath(os.path.dirname(sys.argv[0])) - - -if sys.version_info[0] >= 3: - _system_encoding = sys.getdefaultencoding() - if _system_encoding is None: - _system_encoding = "iso-8859-1" - - def decode_input(data): - if isinstance(data, str): - return data - return data.decode(_system_encoding) -else: - def decode_input(data): - return data - - -def env_var(n): - value = os.getenv(n) - if value: - value = decode_input(value) - if sys.platform == 'win32' and ';' in value: - return value.split(';') - else: - return value.split() - else: - return [] - - -def env_var_name(n): - return "PYXMLSEC_" + n.upper().replace('-', '_') - - -# Option handling: - -def has_option(n): - try: - sys.argv.remove('--%s' % n) - return True - except ValueError: - pass - # allow passing all cmd line options also as environment variables - env_val = os.getenv(env_var_name(n), 'false').lower() - return env_val in ("true", "1") - - -def option_value(n, default=None): - for index, option in enumerate(sys.argv): - if option == '--' + n: - if index+1 >= len(sys.argv): - raise DistutilsOptionError( - 'The option %s requires a value' % option) - value = sys.argv[index+1] - sys.argv[index:index+2] = [] - return value - if option.startswith('--' + n + '='): - value = option[len(n)+3:] - sys.argv[index:index+1] = [] - return value - return os.getenv(env_var_name(n), default) - - -OPTION_ENABLE_DEBUG = has_option('enable-debug') -OPTION_DOWNLOAD_DIR = option_value('download-dir', 'build/extra') From e2a369c9e73add4776158829ecccb4143b3120ca Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 16:59:08 +0200 Subject: [PATCH 244/378] fix libxml2/libxslt version parsing in setup script Signed-off-by: oleg.hoefling --- setup.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/setup.py b/setup.py index da3a0ad4..9a3c9277 100644 --- a/setup.py +++ b/setup.py @@ -285,7 +285,7 @@ def prepare_static_build_linux(self): url = latest_libxml2_release() self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {}'.format(url))) else: - version_prefix, _ = self.libxml2_version.split('.', -1) + version_prefix, _ = self.libxml2_version.rsplit('.', 1) url = 'https://download.gnome.org/sources/libxml2/{}/libxml2-{}.tar.xz'.format( version_prefix, self.libxml2_version ) @@ -305,7 +305,7 @@ def prepare_static_build_linux(self): url = latest_libxslt_release() self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {}'.format(url))) else: - version_prefix, _ = self.libxslt_version.split('.', -1) + version_prefix, _ = self.libxslt_version.rsplit('.', 1) url = 'https://download.gnome.org/sources/libxslt/{}/libxslt-{}.tar.xz'.format( version_prefix, self.libxslt_version ) From 87fb5aa6aae0eb6be81ed46561a299d47aee0df5 Mon Sep 17 00:00:00 2001 From: "oleg.hoefling" Date: Sat, 20 Aug 2022 20:47:38 +0200 Subject: [PATCH 245/378] use python 3.9 in rtd docs builds Signed-off-by: oleg.hoefling --- .readthedocs.yaml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.readthedocs.yaml b/.readthedocs.yaml index f89031d3..93665c84 100644 --- a/.readthedocs.yaml +++ b/.readthedocs.yaml @@ -1,10 +1,14 @@ version: 2 +build: + os: ubuntu-20.04 + tools: + python: '3.9' + sphinx: configuration: doc/source/conf.py python: - version: 3.8 install: - method: pip path: . From 979be38b9819509591a0c542d126ec57918c612d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Sat, 20 Aug 2022 22:39:03 +0200 Subject: [PATCH 246/378] Add CI for Python 3.10, manylinux2, musllinux1 and OpenSUSE Tumbleweed (#225) * add CI for python 3.10 Signed-off-by: oleg.hoefling * skip 3.6 and 3.7 builds for tumbleweed since python versions not available in repo Signed-off-by: oleg.hoefling * build for manylinux2_24 soabi Signed-off-by: oleg.hoefling * try building for musllinux1_1 soabi Signed-off-by: oleg.hoefling * fix wheel selection for auditwheel repair Signed-off-by: oleg.hoefling * use plain parametrization in constants tests instead of hypothesis Signed-off-by: oleg.hoefling * battle zypper Signed-off-by: oleg.hoefling * battle zypper Signed-off-by: oleg.hoefling * battle zypper Signed-off-by: oleg.hoefling * battle zypper Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- .appveyor.yml | 4 +++ .github/workflows/macosx.yml | 2 +- .../{manylinux2010.yml => manylinux.yml} | 23 ++++++++++----- .github/workflows/opensuse-tumbleweed.yml | 29 +++++++++++++++++++ .github/workflows/sdist.yml | 4 +-- requirements-test.txt | 1 - tests/test_constants.py | 10 +++---- 7 files changed, 57 insertions(+), 16 deletions(-) rename .github/workflows/{manylinux2010.yml => manylinux.yml} (75%) create mode 100644 .github/workflows/opensuse-tumbleweed.yml diff --git a/.appveyor.yml b/.appveyor.yml index 9155acc0..de17f8ba 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -12,6 +12,10 @@ environment: python_version: 3.9.13 - python: 39-x64 python_version: 3.9.13 + - python: 310 + python_version: 3.10.6 + - python: 310-x64 + python_version: 3.10.6 install: - ps: | diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index ef72fb78..4db5e306 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [3.5, 3.6, 3.7, 3.8, 3.9] + python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10"] steps: - uses: actions/checkout@v3 - name: Setup Python diff --git a/.github/workflows/manylinux2010.yml b/.github/workflows/manylinux.yml similarity index 75% rename from .github/workflows/manylinux2010.yml rename to .github/workflows/manylinux.yml index d1769b74..867c17ba 100644 --- a/.github/workflows/manylinux2010.yml +++ b/.github/workflows/manylinux.yml @@ -1,12 +1,21 @@ -name: manylinux2010 +name: manylinux on: [push, pull_request] jobs: - manylinux2010_x86_64: + pep513: runs-on: ubuntu-latest - container: quay.io/pypa/manylinux2010_x86_64 strategy: matrix: - python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39] + python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310] + image: + - manylinux2010_x86_64 + - manylinux_2_24_x86_64 + - musllinux_1_1_x86_64 + exclude: + - image: manylinux2010_x86_64 + python-abi: cp310-cp310 + - image: manylinux2010_i686 + python-abi: cp310-cp310 + container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 - name: Install build dependencies @@ -23,13 +32,13 @@ jobs: PYXMLSEC_STATIC_DEPS: true run: | /opt/python/${{ matrix.python-abi }}/bin/python -m build - - name: Label manylinux2010_x86_64 wheel + - name: Label manylinux wheel run: | ls -la dist/ auditwheel show dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl auditwheel repair dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl - ls -l wheelhouse/ - auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-manylinux_2_12_x86_64.manylinux2010_x86_64.whl + ls -la wheelhouse/ + auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-*${{ matrix.image }}*.whl - name: Install test dependencies run: | /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt diff --git a/.github/workflows/opensuse-tumbleweed.yml b/.github/workflows/opensuse-tumbleweed.yml new file mode 100644 index 00000000..d8bb8113 --- /dev/null +++ b/.github/workflows/opensuse-tumbleweed.yml @@ -0,0 +1,29 @@ +name: opensuse-tumbleweed +on: [push, pull_request] +jobs: + tumbleweed: + runs-on: ubuntu-latest + container: opensuse/tumbleweed + strategy: + matrix: + python-version: ["3.8", "3.9", "3.10"] + steps: + - uses: actions/checkout@v1 + - name: Install build dependencies + run: | + zypper -n install -t pattern devel_basis + PKGVER_NO_DOT=$(tr -d '.' <<< ${{ matrix.python-version }}) + zypper -n install git libxmlsec1-openssl1 xmlsec1-openssl-devel python${PKGVER_NO_DOT}-devel python${PKGVER_NO_DOT}-pip + python${{ matrix.python-version }} -m venv .venv + .venv/bin/python -m pip install --upgrade pip setuptools wheel + - name: Build linux_x86_64 wheel + run: | + .venv/bin/python setup.py bdist_wheel + rm -rf build/ + - name: Install test dependencies + run: | + .venv/bin/python -m pip install --upgrade -r requirements-test.txt + .venv/bin/python -m pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + - name: Run tests + run: | + .venv/bin/python -m pytest -v --color=yes diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 28fe79fe..fb13377a 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -5,10 +5,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.9 + - name: Set up Python 3.10 uses: actions/setup-python@v4 with: - python-version: 3.9 + python-version: "3.10" - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel diff --git a/requirements-test.txt b/requirements-test.txt index a2a90bbc..eb543402 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,4 +1,3 @@ -r requirements.txt pytest>=4.6.9 -hypothesis lxml-stubs diff --git a/tests/test_constants.py b/tests/test_constants.py index 689edce6..f79d19f0 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -1,6 +1,6 @@ """Test constants from :mod:`xmlsec.constants` module.""" -from hypothesis import given, strategies +import pytest import xmlsec @@ -18,25 +18,25 @@ def _constants(typename): ) -@given(transform=strategies.sampled_from(_constants('__Transform'))) +@pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr) def test_transform_str(transform): """Test string representation of ``xmlsec.constants.__Transform``.""" assert str(transform) == '{}, {}'.format(transform.name, transform.href) -@given(transform=strategies.sampled_from(_constants('__Transform'))) +@pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr) def test_transform_repr(transform): """Test raw string representation of ``xmlsec.constants.__Transform``.""" assert repr(transform) == '__Transform({!r}, {!r}, {})'.format(transform.name, transform.href, transform.usage) -@given(keydata=strategies.sampled_from(_constants('__KeyData'))) +@pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr) def test_keydata_str(keydata): """Test string representation of ``xmlsec.constants.__KeyData``.""" assert str(keydata) == '{}, {}'.format(keydata.name, keydata.href) -@given(keydata=strategies.sampled_from(_constants('__KeyData'))) +@pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr) def test_keydata_repr(keydata): """Test raw string representation of ``xmlsec.constants.__KeyData``.""" assert repr(keydata) == '__KeyData({!r}, {!r})'.format(keydata.name, keydata.href) From b483b644b6033e539f303509f5ee85bebf178a73 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Sat, 20 Aug 2022 22:54:29 +0200 Subject: [PATCH 247/378] update gh actions badges (#226) Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- README.rst | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) diff --git a/README.rst b/README.rst index 1543f821..b2b3ab11 100644 --- a/README.rst +++ b/README.rst @@ -7,12 +7,14 @@ python-xmlsec :target: https://travis-ci.org/mehcode/python-xmlsec .. image:: https://img.shields.io/appveyor/ci/hoefling/xmlsec/master.svg?logo=appveyor&logoColor=white&label=AppVeyor :target: https://ci.appveyor.com/project/hoefling/xmlsec -.. image:: https://github.com/mehcode/python-xmlsec/workflows/manylinux2010/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22manylinux2010%22 -.. image:: https://github.com/mehcode/python-xmlsec/workflows/MacOS/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22MacOS%22 -.. image:: https://github.com/mehcode/python-xmlsec/workflows/linuxbrew/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions?query=workflow%3A%22linuxbrew%22 +.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml +.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml +.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml +.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml/badge.svg + :target: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml .. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg :target: https://codecov.io/gh/mehcode/python-xmlsec .. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs From 21ce91648b8e09dd9d5c60acab01e849196ad699 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Sun, 21 Aug 2022 00:18:29 +0200 Subject: [PATCH 248/378] allow building docs with python 3.8 (#227) Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- doc/source/conf.py | 18 ++++++++++-------- doc/source/index.rst | 3 --- 2 files changed, 10 insertions(+), 11 deletions(-) diff --git a/doc/source/conf.py b/doc/source/conf.py index 7ff2b1f8..01c2b895 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,7 +1,9 @@ # -*- coding: utf-8 -*- -import sys +from __future__ import annotations + import urllib.request +import importlib.metadata import lxml from docutils.nodes import Text, reference @@ -11,11 +13,6 @@ from sphinx.environment import BuildEnvironment from sphinx.errors import ExtensionError -if sys.version_info >= (3, 8): - from importlib import metadata as importlib_metadata -else: - import importlib_metadata - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] @@ -28,11 +25,10 @@ project = u'python-xmlsec' copyright = u'2020, Oleg Hoefling ' # noqa: A001 author = u'Bulat Gaifullin ' -release = importlib_metadata.version('xmlsec') +release = importlib.metadata.version('xmlsec') parsed: Version = parse(release) version = '{}.{}'.format(parsed.major, parsed.minor) -language = None exclude_patterns: list[str] = [] pygments_style = 'sphinx' todo_include_todos = False @@ -69,6 +65,12 @@ autodoc_member_order = 'groupwise' autodoc_docstring_signature = True + +rst_prolog = ''' +.. role:: xml(code) + :language: xml +''' + # LXML crossref'ing stuff: # LXML doesn't have an intersphinx docs, # so we link to lxml.etree._Element explicitly diff --git a/doc/source/index.rst b/doc/source/index.rst index 5cc758b9..e08f47d9 100644 --- a/doc/source/index.rst +++ b/doc/source/index.rst @@ -3,9 +3,6 @@ You can adapt this file completely to your liking, but it should at least contain the root ``toctree`` directive. -.. role:: xml(code) - :language: xml - Welcome to python-xmlsec's documentation! ========================================= From 00759a33f6cbc2aa62536a1898d8107f88a49e55 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Sun, 21 Aug 2022 00:20:05 +0200 Subject: [PATCH 249/378] add proper param types in register_callbacks (#228) Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- src/main.c | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/main.c b/src/main.c index 41f5e5fc..ffcae14f 100644 --- a/src/main.c +++ b/src/main.c @@ -275,18 +275,23 @@ static PyObject* PyXmlSec_PyIORegisterDefaultCallbacks(PyObject *self) { } static char PyXmlSec_PyIORegisterCallbacks__doc__[] = \ + "register_callbacks(input_match_callback, input_open_callback, input_read_callback, input_close_callback) -> None\n" "Register globally a custom set of IO callbacks with xmlsec.\n\n" - ":param callable input_match_callback: A callable that takes a filename `bytestring` and " + ":param input_match_callback: A callable that takes a filename `bytestring` and " "returns a boolean as to whether the other callbacks in this set can handle that name.\n" - ":param callable input_open_callback: A callable that takes a filename and returns some " + ":type input_match_callback: ~collections.abc.Callable[[bytes], bool]\n" + ":param input_open_callback: A callable that takes a filename and returns some " "context object (e.g. a file object) that the remaining callables in this set will be passed " "during handling.\n" + ":type input_open_callback: ~collections.abc.Callable[[bytes], Any]\n" // FIXME: How do we handle failures in ^^ (e.g. can't find the file)? - ":param callable input_read_callback: A callable that that takes the context object from the " + ":param input_read_callback: A callable that that takes the context object from the " "open callback and a buffer, and should fill the buffer with data (e.g. BytesIO.readinto()). " "xmlsec will call this function several times until there is no more data returned.\n" - ":param callable input_close_callback: A callable that takes the context object from the " + ":type input_read_callback: ~collections.abc.Callable[[Any, memoryview], int]\n" + ":param input_close_callback: A callable that takes the context object from the " "open callback and can do any resource cleanup necessary.\n" + ":type input_close_callback: ~collections.abc.Callable[[Any], None]\n" ; static PyObject* PyXmlSec_PyIORegisterCallbacks(PyObject *self, PyObject *args, PyObject *kwargs) { static char *kwlist[] = { From 824084311638b7a6d07c0e6fa9414f14e84ee713 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Sun, 21 Aug 2022 09:10:09 +0200 Subject: [PATCH 250/378] adjust doc examples to #212 (#229) Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- doc/source/examples/encrypt.py | 11 +++++++---- doc/source/examples/sign.py | 3 ++- doc/source/examples/verify.py | 4 +++- 3 files changed, 12 insertions(+), 6 deletions(-) diff --git a/doc/source/examples/encrypt.py b/doc/source/examples/encrypt.py index f69d4613..98f63b6f 100644 --- a/doc/source/examples/encrypt.py +++ b/doc/source/examples/encrypt.py @@ -2,10 +2,9 @@ import xmlsec -manager = xmlsec.KeysManager() -key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None) -manager.add_key(key) -template = etree.parse('enc1-doc.xml').getroot() +with open('enc1-doc.xml') as fp: + template = etree.parse(fp).getroot() + enc_data = xmlsec.template.encrypted_data_create( template, xmlsec.constants.TransformAes128Cbc, @@ -20,6 +19,10 @@ data = template.find('./Data') # Encryption +manager = xmlsec.KeysManager() +key = xmlsec.Key.from_file('rsacert.pem', xmlsec.constants.KeyDataFormatCertPem, None) +manager.add_key(key) + enc_ctx = xmlsec.EncryptionContext(manager) enc_ctx.key = xmlsec.Key.generate( xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession diff --git a/doc/source/examples/sign.py b/doc/source/examples/sign.py index 4529bc8a..519c13a0 100644 --- a/doc/source/examples/sign.py +++ b/doc/source/examples/sign.py @@ -2,7 +2,8 @@ import xmlsec -template = etree.parse('sign1-tmpl.xml').getroot() +with open('sign1-tmpl.xml') as fp: + template = etree.parse(fp).getroot() signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) ctx = xmlsec.SignatureContext() diff --git a/doc/source/examples/verify.py b/doc/source/examples/verify.py index 8629c550..808a53c2 100644 --- a/doc/source/examples/verify.py +++ b/doc/source/examples/verify.py @@ -2,7 +2,9 @@ import xmlsec -template = etree.parse('sign1-res.xml').getroot() +with open('sign1-res.xml') as fp: + template = etree.parse(fp).getroot() + xmlsec.tree.add_ids(template, ["ID"]) signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) # Create a digital signature context (no key manager is needed). From c39eeff382ed119913463832f2f44d89b90dcc6c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Wed, 24 Aug 2022 20:26:22 +0200 Subject: [PATCH 251/378] Add integration with pre-commit.ci (#230) * add pre-commit.ci badge Signed-off-by: oleg.hoefling * fix pre-commit warnings Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- .pre-commit-config.yaml | 2 +- README.rst | 5 +-- doc/source/conf.py | 5 +-- doc/source/examples/sign_binary.py | 2 -- doc/source/examples/verify_binary.py | 2 -- doc/source/sphinx-pr-6916.diff | 46 ---------------------------- setup.cfg | 3 ++ tests/base.py | 21 +++---------- tests/conftest.py | 5 +-- tests/test_ds.py | 3 +- tests/test_enc.py | 9 +++--- tests/test_main.py | 4 +-- tests/test_xmlsec.py | 6 ++-- 13 files changed, 26 insertions(+), 87 deletions(-) delete mode 100644 doc/source/sphinx-pr-6916.diff diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3080b068..3c89b250 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,6 +1,5 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks -exclude: ".*.diff" # exclude patches repos: - repo: https://github.com/psf/black rev: 22.6.0 @@ -21,6 +20,7 @@ repos: - id: check-merge-conflict - id: check-json - id: detect-private-key + exclude: ^.*/rsakey.pem$ - id: mixed-line-ending - id: pretty-format-json args: [--autofix] diff --git a/README.rst b/README.rst index b2b3ab11..03312504 100644 --- a/README.rst +++ b/README.rst @@ -3,8 +3,9 @@ python-xmlsec .. image:: https://img.shields.io/pypi/v/xmlsec.svg?logo=python&logoColor=white :target: https://pypi.python.org/pypi/xmlsec -.. image:: https://img.shields.io/travis/com/mehcode/python-xmlsec/master.svg?logo=travis&logoColor=white&label=Travis%20CI - :target: https://travis-ci.org/mehcode/python-xmlsec +.. image:: https://results.pre-commit.ci/badge/github/xmlsec/python-xmlsec/master.svg + :target: https://results.pre-commit.ci/latest/github/xmlsec/python-xmlsec/master + :alt: pre-commit.ci status .. image:: https://img.shields.io/appveyor/ci/hoefling/xmlsec/master.svg?logo=appveyor&logoColor=white&label=AppVeyor :target: https://ci.appveyor.com/project/hoefling/xmlsec .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml/badge.svg diff --git a/doc/source/conf.py b/doc/source/conf.py index 01c2b895..35329050 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -1,9 +1,7 @@ -# -*- coding: utf-8 -*- - from __future__ import annotations -import urllib.request import importlib.metadata +import urllib.request import lxml from docutils.nodes import Text, reference @@ -13,7 +11,6 @@ from sphinx.environment import BuildEnvironment from sphinx.errors import ExtensionError - extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode', 'sphinx.ext.intersphinx'] intersphinx_mapping = {'python': ('https://docs.python.org/3/', None)} diff --git a/doc/source/examples/sign_binary.py b/doc/source/examples/sign_binary.py index 4e6c0e00..275c6e40 100644 --- a/doc/source/examples/sign_binary.py +++ b/doc/source/examples/sign_binary.py @@ -1,5 +1,3 @@ -from lxml import etree - import xmlsec ctx = xmlsec.SignatureContext() diff --git a/doc/source/examples/verify_binary.py b/doc/source/examples/verify_binary.py index 06c2b727..1f888b99 100644 --- a/doc/source/examples/verify_binary.py +++ b/doc/source/examples/verify_binary.py @@ -1,5 +1,3 @@ -from lxml import etree - import xmlsec ctx = xmlsec.SignatureContext() diff --git a/doc/source/sphinx-pr-6916.diff b/doc/source/sphinx-pr-6916.diff deleted file mode 100644 index e7040a0f..00000000 --- a/doc/source/sphinx-pr-6916.diff +++ /dev/null @@ -1,46 +0,0 @@ -diff --git a/sphinx/environment/__init__.py b/sphinx/environment/__init__.py -index bc9bf49a74..4804c89c52 100644 ---- a/sphinx/environment/__init__.py -+++ b/sphinx/environment/__init__.py -@@ -46,6 +46,7 @@ - default_settings = { - 'embed_stylesheet': False, - 'cloak_email_addresses': True, -+ 'syntax_highlight': 'short', - 'pep_base_url': 'https://www.python.org/dev/peps/', - 'pep_references': None, - 'rfc_base_url': 'https://tools.ietf.org/html/', -diff --git a/sphinx/writers/html.py b/sphinx/writers/html.py -index 85eeb43..80f1eea 100644 ---- a/sphinx/writers/html.py -+++ b/sphinx/writers/html.py -@@ -494,8 +494,11 @@ class HTMLTranslator(SphinxTranslator, BaseTranslator): - self.body.append(self.starttag(node, 'kbd', '', - CLASS='docutils literal notranslate')) - else: -+ classes = 'docutils literal notranslate' -+ if 'code' in node['classes']: -+ classes += ' highlight' - self.body.append(self.starttag(node, 'code', '', -- CLASS='docutils literal notranslate')) -+ CLASS=classes)) - self.protect_literal_text += 1 - - def depart_literal(self, node: Element) -> None: -diff --git a/sphinx/writers/html5.py b/sphinx/writers/html5.py -index 80cedd3..470f559 100644 ---- a/sphinx/writers/html5.py -+++ b/sphinx/writers/html5.py -@@ -446,8 +446,11 @@ class HTML5Translator(SphinxTranslator, BaseTranslator): - self.body.append(self.starttag(node, 'kbd', '', - CLASS='docutils literal notranslate')) - else: -+ classes = 'docutils literal notranslate' -+ if 'code' in node['classes']: -+ classes += ' highlight' - self.body.append(self.starttag(node, 'code', '', -- CLASS='docutils literal notranslate')) -+ CLASS=classes)) - self.protect_literal_text += 1 - - def depart_literal(self, node: Element) -> None: diff --git a/setup.cfg b/setup.cfg index 88d815b0..c090b4e8 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,5 +18,8 @@ upload_dir = doc/build/html [flake8] per-file-ignores = *.pyi: E301, E302, E305, E501, E701, F401, F822 + doc/source/conf.py: D1 + doc/source/examples/*.py: D1, E501 + tests/*.py: D1 exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv* max-line-length = 130 diff --git a/tests/base.py b/tests/base.py index 06acf413..29605ce7 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,5 +1,6 @@ import gc import os +import resource import sys import unittest @@ -12,20 +13,8 @@ ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs} -try: - import resource - - def get_memory_usage(): - return resource.getrusage(resource.RUSAGE_SELF).ru_maxrss - -except ImportError: - resource = None - - def get_memory_usage(): - return 0 - - def get_iterations(): + """Parse iterations amount.""" if sys.platform in ('win32',): return 0 @@ -114,9 +103,9 @@ def assertXmlEqual(self, first, second, msg=None): # noqa: N802 for name in second.attrib.keys(): if name not in first.attrib: self.fail('x2 has an attribute x1 is missing: {}. {}'.format(name, msg)) - if not xml_text_compare(first.text, second.text): + if not _xml_text_compare(first.text, second.text): self.fail('text: {!r} != {!r}. {}'.format(first.text, second.text, msg)) - if not xml_text_compare(first.tail, second.tail): + if not _xml_text_compare(first.tail, second.tail): self.fail('tail: {!r} != {!r}. {}'.format(first.tail, second.tail, msg)) cl1 = sorted(first.getchildren(), key=lambda x: x.tag) cl2 = sorted(second.getchildren(), key=lambda x: x.tag) @@ -128,7 +117,7 @@ def assertXmlEqual(self, first, second, msg=None): # noqa: N802 self.assertXmlEqual(c1, c2) -def xml_text_compare(t1, t2): +def _xml_text_compare(t1, t2): if not t1 and not t2: return True if t1 == '*' or t2 == '*': diff --git a/tests/conftest.py b/tests/conftest.py index b51c4d45..675258c5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,7 +1,8 @@ def pytest_collection_modifyitems(items): """ - Put the module init test first to implicitly check whether - any subsequent test fails because of module reinitialization. + Put the module init test first. + + This way, we implicitly check whether any subsequent test fails because of module reinitialization. """ def module_init_tests_first(item): diff --git a/tests/test_ds.py b/tests/test_ds.py index 9417fedb..694ad431 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -132,7 +132,6 @@ def test_sign_case3(self): def test_sign_case4(self): """Should sign a file using a dynamically created template, key from PEM and an X509 cert with custom ns.""" - root = self.load_xml("sign4-in.xml") xmlsec.tree.add_ids(root, ["ID"]) elem_id = root.get('ID', None) @@ -249,7 +248,7 @@ def test_verify_case_5(self): self.check_verify(5) def check_verify(self, i): - root = self.load_xml("sign%d-out.xml" % i) + root = self.load_xml("sign{}-out.xml".format(i)) xmlsec.tree.add_ids(root, ["ID"]) sign = xmlsec.tree.find_node(root, consts.NodeSignature) self.assertIsNotNone(sign) diff --git a/tests/test_enc.py b/tests/test_enc.py index 7add848c..63e00169 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -1,4 +1,3 @@ -import os import tempfile from lxml import etree @@ -125,7 +124,7 @@ def test_encrypt_binary(self): encrypted = ctx.encrypt_binary(enc_data, b'test') self.assertIsNotNone(encrypted) - self.assertEqual("{%s}%s" % (consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag) enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method) @@ -170,7 +169,7 @@ def test_encrypt_uri(self): encrypted = ctx.encrypt_binary(enc_data, 'file://' + tmpfile.name) self.assertIsNotNone(encrypted) - self.assertEqual("{%s}%s" % (consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag) enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method) @@ -219,7 +218,7 @@ def test_decrypt_key(self): self.assertEqual(self.load_xml("enc3-in.xml"), decrypted) def check_decrypt(self, i): - root = self.load_xml('enc%d-out.xml' % i) + root = self.load_xml('enc{}-out.xml'.format(i)) enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs) self.assertIsNotNone(enc_data) @@ -228,7 +227,7 @@ def check_decrypt(self, i): ctx = xmlsec.EncryptionContext(manager) decrypted = ctx.decrypt(enc_data) self.assertIsNotNone(decrypted) - self.assertEqual(self.load_xml("enc%d-in.xml" % i), root) + self.assertEqual(self.load_xml("enc{}-in.xml".format(i)), root) def test_decrypt_bad_args(self): ctx = xmlsec.EncryptionContext() diff --git a/tests/test_main.py b/tests/test_main.py index 9fb71eaf..3db18582 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -112,7 +112,7 @@ def test_sign_data_not_first_callback(self): def match_cb(filename): nonlocal bad_match_calls bad_match_calls += 1 - False + return False for _ in range(2): self._register_mismatch_callbacks(match_cb) @@ -132,7 +132,7 @@ def test_failed_sign_because_default_callbacks(self): def mismatch_cb(filename): nonlocal mismatch_calls mismatch_calls += 1 - False + return False # NB: These first two sets of callbacks should never get called, # because the default callbacks always match beforehand: diff --git a/tests/test_xmlsec.py b/tests/test_xmlsec.py index 32fac69a..303d7f8f 100644 --- a/tests/test_xmlsec.py +++ b/tests/test_xmlsec.py @@ -5,9 +5,9 @@ class TestModule(base.TestMemoryLeaks): def test_reinitialize_module(self): """ - This doesn't explicitly test anything, but will - be invoked first in the suite, so if the subsequent - tests don't fail, we know that the ``init()``/``shutdown()`` + This test doesn't explicitly verify anything, but will be invoked first in the suite. + + So if the subsequent tests don't fail, we know that the ``init()``/``shutdown()`` function pair doesn't break anything. """ xmlsec.shutdown() From 91592052b671d0ccb34a51ff84534cd684ea1473 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Wed, 24 Aug 2022 20:53:17 +0200 Subject: [PATCH 252/378] fix test run on appveyor (#231) Signed-off-by: oleg.hoefling Signed-off-by: oleg.hoefling --- tests/base.py | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/tests/base.py b/tests/base.py index 29605ce7..48aef81d 100644 --- a/tests/base.py +++ b/tests/base.py @@ -1,6 +1,5 @@ import gc import os -import resource import sys import unittest @@ -8,26 +7,23 @@ import xmlsec -etype = type(etree.Element("test")) +etype = type(etree.Element('test')) ns = {'dsig': xmlsec.constants.DSigNs, 'enc': xmlsec.constants.EncNs} -def get_iterations(): - """Parse iterations amount.""" - if sys.platform in ('win32',): - return 0 +try: + import resource - try: - return int(os.getenv("PYXMLSEC_TEST_ITERATIONS", "10")) - except ValueError: - return 0 + test_iterations = int(os.environ.get('PYXMLSEC_TEST_ITERATIONS', '10')) +except (ImportError, ValueError): + test_iterations = 0 class TestMemoryLeaks(unittest.TestCase): maxDiff = None - iterations = get_iterations() + iterations = test_iterations data_dir = os.path.join(os.path.dirname(__file__), "data") From e83a4576f0a879acc5594e204bf6a485781d6427 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 6 Sep 2022 11:09:21 +0200 Subject: [PATCH 253/378] [pre-commit.ci] pre-commit autoupdate (#233) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 22.6.0 → 22.8.0](https://github.com/psf/black/compare/22.6.0...22.8.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3c89b250..75e4b7ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black - rev: 22.6.0 + rev: 22.8.0 hooks: - id: black types: [] From c4658f37c9df3d9ecd90fa42878b5ae92afa79a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Oleg=20H=C3=B6fling?= Date: Thu, 29 Sep 2022 17:47:18 +0200 Subject: [PATCH 254/378] Correct codecov badge URL in readme --- README.rst | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.rst b/README.rst index 03312504..34bdd377 100644 --- a/README.rst +++ b/README.rst @@ -16,8 +16,8 @@ python-xmlsec :target: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml .. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml/badge.svg :target: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml -.. image:: https://codecov.io/gh/mehcode/python-xmlsec/branch/master/graph/badge.svg - :target: https://codecov.io/gh/mehcode/python-xmlsec +.. image:: https://codecov.io/gh/xmlsec/python-xmlsec/branch/master/graph/badge.svg + :target: https://codecov.io/gh/xmlsec/python-xmlsec .. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest :alt: Documentation Status From cc8632f4f3181cdee6f325c47b2dde08117b5f55 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Oct 2022 08:06:32 +0200 Subject: [PATCH 255/378] [pre-commit.ci] pre-commit autoupdate (#238) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/mirrors-mypy: v0.971 → v0.981](https://github.com/pre-commit/mirrors-mypy/compare/v0.971...v0.981) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 75e4b7ab..0545b12f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -35,7 +35,7 @@ repos: hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.971 + rev: v0.981 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From 92882809a0c380a8689ab0e7a995803decb2cc59 Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 13:58:25 +0100 Subject: [PATCH 256/378] Added changes to enable 3.11 builds --- .appveyor.yml | 4 ++++ .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux.yml | 6 +++--- .github/workflows/opensuse-tumbleweed.yml | 2 +- .github/workflows/sdist.yml | 4 ++-- .travis.yml | 3 +++ setup.py | 1 + 7 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index de17f8ba..b580525f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -16,6 +16,10 @@ environment: python_version: 3.10.6 - python: 310-x64 python_version: 3.10.6 + - python: 311 + python_version: 3.11.2 + - python: 311-x64 + python_version: 3.10.6 install: - ps: | diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 4db5e306..24fa6ddd 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10"] + python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] steps: - uses: actions/checkout@v3 - name: Setup Python diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 867c17ba..520e5ba6 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -5,16 +5,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310] + python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] image: - manylinux2010_x86_64 - manylinux_2_24_x86_64 - musllinux_1_1_x86_64 exclude: - image: manylinux2010_x86_64 - python-abi: cp310-cp310 + python-abi: cp311-cp311 - image: manylinux2010_i686 - python-abi: cp310-cp310 + python-abi: cp311-cp311 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/opensuse-tumbleweed.yml b/.github/workflows/opensuse-tumbleweed.yml index d8bb8113..273f7f7f 100644 --- a/.github/workflows/opensuse-tumbleweed.yml +++ b/.github/workflows/opensuse-tumbleweed.yml @@ -6,7 +6,7 @@ jobs: container: opensuse/tumbleweed strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v1 - name: Install build dependencies diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index fb13377a..d7959208 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -5,10 +5,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel diff --git a/.travis.yml b/.travis.yml index 9106805a..9e6ca540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,9 @@ matrix: - python: 3.9 dist: xenial sudo: required + - python: 3.11 + dist: xenial + sudo: required env: global: - CFLAGS=-coverage diff --git a/setup.py b/setup.py index 9a3c9277..5c7e0da5 100644 --- a/setup.py +++ b/setup.py @@ -533,6 +533,7 @@ def prepare_static_build_linux(self): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.11', 'Topic :: Text Processing :: Markup :: XML', 'Typing :: Typed', ], From d16f9853e9c85b97428d467b82fcf2fa5c766abf Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 14:00:32 +0100 Subject: [PATCH 257/378] Added changes to enable 3.11 builds --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index b580525f..ce025819 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,7 +19,7 @@ environment: - python: 311 python_version: 3.11.2 - python: 311-x64 - python_version: 3.10.6 + python_version: 3.11.2 install: - ps: | From 519feff7d36389363122472d6a68aa285ed3405d Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 14:52:40 +0100 Subject: [PATCH 258/378] bumped isort to 5.11.5 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0545b12f..6b8fdf67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.11.5 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy From 156394743a0c712e6638fe6e7e300c2f24b4fb12 Mon Sep 17 00:00:00 2001 From: tdivis Date: Fri, 24 Mar 2023 08:03:26 +0100 Subject: [PATCH 259/378] Fix #247 - Fix missing import of `template` in `__init__.pyi` stub. (#248) --- src/xmlsec/__init__.pyi | 1 + 1 file changed, 1 insertion(+) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index be0bd659..56356e55 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -5,6 +5,7 @@ from _typeshed import GenericPath, Self, StrOrBytesPath from lxml.etree import _Element from xmlsec import constants as constants +from xmlsec import template as template from xmlsec import tree as tree from xmlsec.constants import __KeyData as KeyData from xmlsec.constants import __Transform as Transform From a7f95d55cd660d1a212fa76a527063b3b7dbe8bb Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 13:58:25 +0100 Subject: [PATCH 260/378] Added changes to enable 3.11 builds --- .appveyor.yml | 4 ++++ .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux.yml | 6 +++--- .github/workflows/opensuse-tumbleweed.yml | 2 +- .github/workflows/sdist.yml | 4 ++-- .travis.yml | 3 +++ setup.py | 1 + 7 files changed, 15 insertions(+), 7 deletions(-) diff --git a/.appveyor.yml b/.appveyor.yml index de17f8ba..b580525f 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -16,6 +16,10 @@ environment: python_version: 3.10.6 - python: 310-x64 python_version: 3.10.6 + - python: 311 + python_version: 3.11.2 + - python: 311-x64 + python_version: 3.10.6 install: - ps: | diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 4db5e306..24fa6ddd 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10"] + python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] steps: - uses: actions/checkout@v3 - name: Setup Python diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 867c17ba..520e5ba6 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -5,16 +5,16 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310] + python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] image: - manylinux2010_x86_64 - manylinux_2_24_x86_64 - musllinux_1_1_x86_64 exclude: - image: manylinux2010_x86_64 - python-abi: cp310-cp310 + python-abi: cp311-cp311 - image: manylinux2010_i686 - python-abi: cp310-cp310 + python-abi: cp311-cp311 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 diff --git a/.github/workflows/opensuse-tumbleweed.yml b/.github/workflows/opensuse-tumbleweed.yml index d8bb8113..273f7f7f 100644 --- a/.github/workflows/opensuse-tumbleweed.yml +++ b/.github/workflows/opensuse-tumbleweed.yml @@ -6,7 +6,7 @@ jobs: container: opensuse/tumbleweed strategy: matrix: - python-version: ["3.8", "3.9", "3.10"] + python-version: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v1 - name: Install build dependencies diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index fb13377a..d7959208 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -5,10 +5,10 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - - name: Set up Python 3.10 + - name: Set up Python 3.11 uses: actions/setup-python@v4 with: - python-version: "3.10" + python-version: "3.11" - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel diff --git a/.travis.yml b/.travis.yml index 9106805a..9e6ca540 100644 --- a/.travis.yml +++ b/.travis.yml @@ -16,6 +16,9 @@ matrix: - python: 3.9 dist: xenial sudo: required + - python: 3.11 + dist: xenial + sudo: required env: global: - CFLAGS=-coverage diff --git a/setup.py b/setup.py index 9a3c9277..5c7e0da5 100644 --- a/setup.py +++ b/setup.py @@ -533,6 +533,7 @@ def prepare_static_build_linux(self): 'Programming Language :: Python :: 3.7', 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.11', 'Topic :: Text Processing :: Markup :: XML', 'Typing :: Typed', ], From b7683774f747c7aed6a0b30e6045da679bc68760 Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 14:00:32 +0100 Subject: [PATCH 261/378] Added changes to enable 3.11 builds --- .appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.appveyor.yml b/.appveyor.yml index b580525f..ce025819 100644 --- a/.appveyor.yml +++ b/.appveyor.yml @@ -19,7 +19,7 @@ environment: - python: 311 python_version: 3.11.2 - python: 311-x64 - python_version: 3.10.6 + python_version: 3.11.2 install: - ps: | From bddf28e68a2509a287f9889aaeadc3adab80ccbc Mon Sep 17 00:00:00 2001 From: Dan Vella Date: Fri, 17 Mar 2023 14:52:40 +0100 Subject: [PATCH 262/378] bumped isort to 5.11.5 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0545b12f..6b8fdf67 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.11.5 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy From 2c58d43eedf72590e3e201252f5fc5ddae36f8c6 Mon Sep 17 00:00:00 2001 From: Tomas Divis Date: Wed, 22 Mar 2023 20:36:45 +0100 Subject: [PATCH 263/378] Fix #244 - Fix failing test with libxmlsec-1.2.36, also make libxmlsec version available from Python. --- src/main.c | 13 ++++ tests/data/sign5-out-xmlsec_1_2_36_to_37.xml | 67 ++++++++++++++++++++ tests/test_ds.py | 6 +- 3 files changed, 85 insertions(+), 1 deletion(-) create mode 100644 tests/data/sign5-out-xmlsec_1_2_36_to_37.xml diff --git a/src/main.c b/src/main.c index ffcae14f..5773db3b 100644 --- a/src/main.c +++ b/src/main.c @@ -119,6 +119,13 @@ static PyObject* PyXmlSec_PyShutdown(PyObject* self) { Py_RETURN_NONE; } +static char PyXmlSec_GetLibXmlSecVersion__doc__[] = \ + "get_libxmlsec_version() -> tuple\n" + "Returns Version tuple of wrapped libxml library."; +static PyObject* PyXmlSec_GetLibXmlSecVersion() { + return Py_BuildValue("(iii)", XMLSEC_VERSION_MAJOR, XMLSEC_VERSION_MINOR, XMLSEC_VERSION_SUBMINOR); +} + static char PyXmlSec_PyEnableDebugOutput__doc__[] = \ "enable_debug_trace(enabled) -> None\n" "Enables or disables calling LibXML2 callback from the default errors callback.\n\n" @@ -386,6 +393,12 @@ static PyMethodDef PyXmlSec_MainMethods[] = { METH_NOARGS, PyXmlSec_PyShutdown__doc__ }, + { + "get_libxmlsec_version", + (PyCFunction)PyXmlSec_GetLibXmlSecVersion, + METH_NOARGS, + PyXmlSec_GetLibXmlSecVersion__doc__ + }, { "enable_debug_trace", (PyCFunction)PyXmlSec_PyEnableDebugOutput, diff --git a/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml b/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml new file mode 100644 index 00000000..f359b138 --- /dev/null +++ b/tests/data/sign5-out-xmlsec_1_2_36_to_37.xml @@ -0,0 +1,67 @@ + + + + + Hello, World! + + + + + + + + + + +HjY8ilZAIEM2tBbPn5mYO1ieIX4= + + +SIaj/6KY3C1SmDXU2++Gm31U1xTadFp04WhBgfsJFbxrL+q7GKSKN9kfQ+UpN9+i +D5fWmuavXEHe4Gw6RMaMEkq2URQo7F68+d5J/ajq8/l4n+xE6/reGScVwT6L4dEP +XXVJcAi2ZnQ3O7GTNvNGCPibL9mUcyCWBFZ92Uemtc/vJFCQ7ZyKMdMfACgxOwyN +T/9971oog241/2doudhonc0I/3mgPYWkZdX6yvr62mEjnG+oUZkhWYJ4ewZJ4hM4 +JjbFqZO+OEzDRSbw3DkmuBA/mtlx+3t13SESfEub5hqoMdVmtth/eTb64dsPdl9r +3k1ACVX9f8aHfQQdJOmLFQ== + + + + + + +Test Issuer +1 + +MIIE3zCCBEigAwIBAgIBBTANBgkqhkiG9w0BAQQFADCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMB4X +DTAzMDMzMTA0MDIyMloXDTEzMDMyODA0MDIyMlowgb8xCzAJBgNVBAYTAlVTMRMw +EQYDVQQIEwpDYWxpZm9ybmlhMT0wOwYDVQQKEzRYTUwgU2VjdXJpdHkgTGlicmFy +eSAoaHR0cDovL3d3dy5hbGVrc2V5LmNvbS94bWxzZWMpMSEwHwYDVQQLExhFeGFt +cGxlcyBSU0EgQ2VydGlmaWNhdGUxFjAUBgNVBAMTDUFsZWtzZXkgU2FuaW4xITAf +BgkqhkiG9w0BCQEWEnhtbHNlY0BhbGVrc2V5LmNvbTCCASIwDQYJKoZIhvcNAQEB +BQADggEPADCCAQoCggEBAJe4/rQ/gzV4FokE7CthjL/EXwCBSkXm2c3p4jyXO0Wt +quaNC3dxBwFPfPl94hmq3ZFZ9PHPPbp4RpYRnLZbRjlzVSOq954AXOXpSew7nD+E +mTqQrd9+ZIbGJnLOMQh5fhMVuOW/1lYCjWAhTCcYZPv7VXD2M70vVXDVXn6ZrqTg +qkVHE6gw1aCKncwg7OSOUclUxX8+Zi10v6N6+PPslFc5tKwAdWJhVLTQ4FKG+F53 +7FBDnNK6p4xiWryy/vPMYn4jYGvHUUk3eH4lFTCr+rSuJY8i/KNIf/IKim7g/o3w +Ae3GM8xrof2mgO8GjK/2QDqOQhQgYRIf4/wFsQXVZcMCAwEAAaOCAVcwggFTMAkG +A1UdEwQCMAAwLAYJYIZIAYb4QgENBB8WHU9wZW5TU0wgR2VuZXJhdGVkIENlcnRp +ZmljYXRlMB0GA1UdDgQWBBQkhCzy1FkgYosuXIaQo6owuicanDCB+AYDVR0jBIHw +MIHtgBS0ue+a5pcOaGUemM76VQ2JBttMfKGB0aSBzjCByzELMAkGA1UEBhMCVVMx +EzARBgNVBAgTCkNhbGlmb3JuaWExEjAQBgNVBAcTCVN1bm55dmFsZTE9MDsGA1UE +ChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20v +eG1sc2VjKTEZMBcGA1UECxMQUm9vdCBDZXJ0aWZpY2F0ZTEWMBQGA1UEAxMNQWxl +a3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggEA +MA0GCSqGSIb3DQEBBAUAA4GBALU/mzIxSv8vhDuomxFcplzwdlLZbvSQrfoNkMGY +1UoS3YJrN+jZLWKSyWE3mIaPpElqXiXQGGkwD5iPQ1iJMbI7BeLvx6ZxX/f+c8Wn +ss0uc1NxfahMaBoyG15IL4+beqO182fosaKJTrJNG3mc//ANGU9OsQM9mfBEt4oL +NJ2D + + + + + diff --git a/tests/test_ds.py b/tests/test_ds.py index 694ad431..38f0b25c 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -182,7 +182,11 @@ def test_sign_case5(self): self.assertEqual("rsakey.pem", ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign5-out.xml"), root) + if (1, 2, 36) <= xmlsec.get_libxmlsec_version() <= (1, 2, 37): + expected_xml_file = 'sign5-out-xmlsec_1_2_36_to_37.xml' + else: + expected_xml_file = 'sign5-out.xml' + self.assertEqual(self.load_xml(expected_xml_file), root) def test_sign_binary_bad_args(self): ctx = xmlsec.SignatureContext() From 1cf6785b3e06c2b8f6cac1266cf8f1934650bc4b Mon Sep 17 00:00:00 2001 From: Tomas Divis Date: Wed, 21 Dec 2022 14:01:14 +0100 Subject: [PATCH 264/378] Fix #164 - Add support for loading keys from engine (e.g. pkcs11). --- README.rst | 2 +- src/keys.c | 47 +++++++++++++++++++++++++++++++++++++++++ src/xmlsec/__init__.pyi | 2 ++ 3 files changed, 50 insertions(+), 1 deletion(-) diff --git a/README.rst b/README.rst index 34bdd377..e1924652 100644 --- a/README.rst +++ b/README.rst @@ -37,7 +37,7 @@ Check the `examples `_ se Requirements ************ - ``libxml2 >= 2.9.1`` -- ``libxmlsec1 >= 1.2.18`` +- ``libxmlsec1 >= 1.2.33`` Install ******* diff --git a/src/keys.c b/src/keys.c index 1362b128..1440331c 100644 --- a/src/keys.c +++ b/src/keys.c @@ -185,6 +185,47 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* return NULL; } +static const char PyXmlSec_KeyFromEngine__doc__[] = \ + "from_engine(engine_and_key_id) -> xmlsec.Key\n" + "Loads PKI key from an engine.\n\n" + ":param engine_and_key_id: engine and key id, i.e. 'pkcs11;pkcs11:token=XmlsecToken;object=XmlsecKey;pin-value=password'\n" + ":type engine_and_key_id: :class:`str`, " + ":return: pointer to newly created key\n" + ":rtype: :class:`~xmlsec.Key`"; +static PyObject* PyXmlSec_KeyFromEngine(PyObject* self, PyObject* args, PyObject* kwargs) { + static char *kwlist[] = {"engine_and_key_id", NULL}; + + const char* engine_and_key_id = NULL; + PyXmlSec_Key* key = NULL; + + PYXMLSEC_DEBUG("load key from engine - start"); + if (!PyArg_ParseTupleAndKeywords(args, kwargs, "s:from_engine", kwlist, &engine_and_key_id)) { + goto ON_FAIL; + } + + if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; + + Py_BEGIN_ALLOW_THREADS; + key->handle = xmlSecCryptoAppKeyLoad(engine_and_key_id, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), + (void*)engine_and_key_id); + Py_END_ALLOW_THREADS; + + if (key->handle == NULL) { + PyXmlSec_SetLastError("cannot read key"); + goto ON_FAIL; + } + + key->is_own = 1; + + PYXMLSEC_DEBUG("load key from engine - ok"); + return (PyObject*)key; + +ON_FAIL: + PYXMLSEC_DEBUG("load key from engine - fail"); + Py_XDECREF(key); + return NULL; +} + static const char PyXmlSec_KeyGenerate__doc__[] = \ "generate(klass, size, type) -> xmlsec.Key\n" "Generates key of kind ``klass`` with ``size`` and ``type``.\n\n" @@ -494,6 +535,12 @@ static PyMethodDef PyXmlSec_KeyMethods[] = { METH_CLASS|METH_VARARGS|METH_KEYWORDS, PyXmlSec_KeyFromFile__doc__ }, + { + "from_engine", + (PyCFunction)PyXmlSec_KeyFromEngine, + METH_CLASS|METH_VARARGS|METH_KEYWORDS, + PyXmlSec_KeyFromEngine__doc__ + }, { "generate", (PyCFunction)PyXmlSec_KeyGenerate, diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 56356e55..6c326f56 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -49,6 +49,8 @@ class Key: @classmethod def from_file(cls: type[Self], file: GenericPath[AnyStr] | IO[AnyStr], format: int, password: str | None = ...) -> Self: ... @classmethod + def from_engine(cls: type[Self], engine_and_key_id: AnyStr) -> Self: ... + @classmethod def from_memory(cls: type[Self], data: AnyStr, format: int, password: str | None = ...) -> Self: ... @classmethod def generate(cls: type[Self], klass: KeyData, size: int, type: int) -> Self: ... From 0b5939fc65e98cebb669d311b4fb58844bf887e5 Mon Sep 17 00:00:00 2001 From: Tomas Divis Date: Thu, 13 Apr 2023 14:28:02 +0200 Subject: [PATCH 265/378] Fix #164 - Add tests for pkcs11 (softhsm) key. --- .github/workflows/sdist.yml | 3 +- tests/softhsm_setup.py | 265 ++++++++++++++++++++++++++++++++++++ tests/test_pkcs11.py | 57 ++++++++ 3 files changed, 323 insertions(+), 2 deletions(-) create mode 100644 tests/softhsm_setup.py create mode 100644 tests/test_pkcs11.py diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index d7959208..6ca7a657 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -16,9 +16,8 @@ jobs: run: | python setup.py sdist - name: Install test dependencies - env: - PYXMLSEC_STATIC_DEPS: true run: | + sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl pip install --upgrade -r requirements-test.txt pip install black # for stub generation tests pip install dist/xmlsec-$(python setup.py --version).tar.gz diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py new file mode 100644 index 00000000..0a7c37de --- /dev/null +++ b/tests/softhsm_setup.py @@ -0,0 +1,265 @@ +""" +Testing the PKCS#11 shim layer. +Heavily inspired by from https://github.com/IdentityPython/pyXMLSecurity by leifj +under licence "As is", see https://github.com/IdentityPython/pyXMLSecurity/blob/master/LICENSE.txt +""" + +import logging +import os +import shutil +import subprocess +import tempfile +import traceback +import unittest +from typing import Dict, List, Optional, Tuple + +DATA_DIR = os.path.join(os.path.dirname(__file__), "data") + + +def paths_for_component(component: str, default_paths: List[str]): + env_path = os.environ.get(component) + return [env_path] if env_path else default_paths + + +def find_alts(component_name, alts: List[str]) -> str: + for a in alts: + if os.path.exists(a): + return a + raise unittest.SkipTest("Required component is missing: {}".format(component_name)) + + +def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: + env = {} + if softhsm_conf is not None: + env['SOFTHSM_CONF'] = softhsm_conf + env['SOFTHSM2_CONF'] = softhsm_conf + proc = subprocess.Popen(args, stdout=subprocess.PIPE, stderr=subprocess.PIPE, env=env) + out, err = proc.communicate() + if err is not None and len(err) > 0: + logging.error(err) + if out is not None and len(out) > 0: + logging.debug(out) + rv = proc.wait() + if rv: + with open(softhsm_conf) as f: + conf = f.read() + msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]' + msg = msg.format( + cmd=" ".join(args), code=rv, out=out.strip(), err=err.strip(), conf=conf, + ) + raise RuntimeError(msg) + return out, err + + +component_default_paths: Dict[str, List[str]] = { + 'P11_MODULE': [ + '/usr/lib/softhsm/libsofthsm2.so', + '/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so', + '/usr/lib/softhsm/libsofthsm.so', + '/usr/lib64/softhsm/libsofthsm2.so', + ], + 'P11_ENGINE': [ + '/usr/lib/ssl/engines/libpkcs11.so', + '/usr/lib/engines/engine_pkcs11.so', + '/usr/lib/x86_64-linux-gnu/engines-1.1/pkcs11.so', + '/usr/lib64/engines-1.1/pkcs11.so', + '/usr/lib64/engines-1.1/libpkcs11.so', + '/usr/lib64/engines-3/pkcs11.so', + '/usr/lib64/engines-3/libpkcs11.so', + '/usr/lib/x86_64-linux-gnu/engines-3/pkcs11.so', + '/usr/lib/x86_64-linux-gnu/engines-3/libpkcs11.so', + ], + 'PKCS11_TOOL': [ + '/usr/bin/pkcs11-tool', + ], + 'SOFTHSM': [ + '/usr/bin/softhsm2-util', + '/usr/bin/softhsm', + ], + 'OPENSSL': [ + '/usr/bin/openssl', + ], +} + +component_path: Dict[str, str] = { + component_name: find_alts(component_name, paths_for_component(component_name, default_paths)) + for component_name, default_paths in component_default_paths.items() +} + +softhsm_version = 1 +if component_path['SOFTHSM'].endswith('softhsm2-util'): + softhsm_version = 2 + +openssl_version = subprocess.check_output([component_path['OPENSSL'], + 'version'] + )[8:11].decode() + +p11_test_files: List[str] = [] +softhsm_conf: Optional[str] = None +softhsm_db: Optional[str] = None + + +def _temp_file() -> str: + f = tempfile.NamedTemporaryFile(delete=False) + p11_test_files.append(f.name) + return f.name + + +def _temp_dir() -> str: + d = tempfile.mkdtemp() + p11_test_files.append(d) + return d + + +@unittest.skipIf(component_path['P11_MODULE'] is None, "SoftHSM PKCS11 module not installed") +def setup() -> None: + logging.debug("Creating test pkcs11 token using softhsm") + try: + global softhsm_conf + softhsm_conf = _temp_file() + logging.debug("Generating softhsm.conf") + with open(softhsm_conf, "w") as f: + if softhsm_version == 2: + softhsm_db = _temp_dir() + f.write(""" +# Generated by test +directories.tokendir = %s +objectstore.backend = file +log.level = DEBUG +""" % softhsm_db) + else: + softhsm_db = _temp_file() + f.write(""" +# Generated by test +0:%s +""" % softhsm_db) + + logging.debug("Initializing the token") + out, err = run_cmd([component_path['SOFTHSM'], + '--slot', '0', + '--label', 'test', + '--init-token', + '--pin', 'secret1', + '--so-pin', 'secret2'], + softhsm_conf=softhsm_conf) + + # logging.debug("Generating 1024 bit RSA key in token") + # run_cmd([component_path['PKCS11_TOOL'], + # '--module', component_path['P11_MODULE'], + # '-l', + # '-k', + # '--key-type', 'rsa:1024', + # '--id', 'a1b2', + # '--label', 'test', + # '--pin', 'secret1'], softhsm_conf=softhsm_conf) + + hash_priv_key = _temp_file() + logging.debug("Converting test private key to format for softhsm") + run_cmd([component_path['OPENSSL'], 'pkcs8', + '-topk8', + '-inform', 'PEM', + '-outform', 'PEM', + '-nocrypt', + '-in', os.path.join(DATA_DIR, 'rsakey.pem'), + '-out', hash_priv_key], softhsm_conf=softhsm_conf) + + logging.debug("Importing the test key to softhsm") + run_cmd([component_path['SOFTHSM'], + '--import', hash_priv_key, + '--token', 'test', + '--id', 'a1b2', + '--label', 'test', + '--pin', 'secret1'], + softhsm_conf=softhsm_conf) + run_cmd([component_path['PKCS11_TOOL'], + '--module', component_path['P11_MODULE'], + '-l', + '--pin', 'secret1', '-O'], softhsm_conf=softhsm_conf) + signer_cert_pem = _temp_file() + openssl_conf = _temp_file() + logging.debug("Generating OpenSSL config for version {}".format(openssl_version)) + with open(openssl_conf, "w") as f: + # Might be needed with some versions of openssl, but in more recent versions dynamic_path breaks it. + # dynamic_path = ( + # "dynamic_path = %s" % component_path['P11_ENGINE'] + # if openssl_version.startswith(b'1.') + # else "" + # ) + f.write("\n".join([ + "openssl_conf = openssl_def", + "[openssl_def]", + "engines = engine_section", + "[engine_section]", + "pkcs11 = pkcs11_section", + "[req]", + "distinguished_name = req_distinguished_name", + "[req_distinguished_name]", + "[pkcs11_section]", + "engine_id = pkcs11", + # dynamic_path, + "MODULE_PATH = %s" % component_path['P11_MODULE'], + "init = 0", + ])) + + with open(openssl_conf, "r") as f: + logging.debug('-------- START DEBUG openssl_conf --------') + logging.debug(f.readlines()) + logging.debug('-------- END DEBUG openssl_conf --------') + logging.debug('-------- START DEBUG paths --------') + logging.debug(run_cmd(['ls', '-ld', component_path['P11_ENGINE']])) + logging.debug(run_cmd(['ls', '-ld', component_path['P11_MODULE']])) + logging.debug('-------- END DEBUG paths --------') + + signer_cert_der = _temp_file() + + logging.debug("Generating self-signed certificate") + run_cmd([component_path['OPENSSL'], 'req', + '-new', + '-x509', + '-subj', "/CN=Test Signer", + '-engine', 'pkcs11', + '-config', openssl_conf, + '-keyform', 'engine', + '-key', 'label_test', + '-passin', 'pass:secret1', + '-out', signer_cert_pem], softhsm_conf=softhsm_conf) + + run_cmd([component_path['OPENSSL'], 'x509', + '-inform', 'PEM', + '-outform', 'DER', + '-in', signer_cert_pem, + '-out', signer_cert_der], softhsm_conf=softhsm_conf) + + logging.debug("Importing certificate into token") + + run_cmd([component_path['PKCS11_TOOL'], + '--module', component_path['P11_MODULE'], + '-l', + '--slot-index', '0', + '--id', 'a1b2', + '--label', 'test', + '-y', 'cert', + '-w', signer_cert_der, + '--pin', 'secret1'], softhsm_conf=softhsm_conf) + + # TODO: Should be teardowned in teardown: + os.environ['SOFTHSM_CONF'] = softhsm_conf + os.environ['SOFTHSM2_CONF'] = softhsm_conf + + except Exception as ex: + print("-" * 64) + traceback.print_exc() + print("-" * 64) + logging.error("PKCS11 tests disabled: unable to initialize test token: %s" % ex) + raise ex + + +def teardown() -> None: + global p11_test_files + for o in p11_test_files: + if os.path.exists(o): + if os.path.isdir(o): + shutil.rmtree(o) + else: + os.unlink(o) + p11_test_files = [] diff --git a/tests/test_pkcs11.py b/tests/test_pkcs11.py new file mode 100644 index 00000000..accd29ae --- /dev/null +++ b/tests/test_pkcs11.py @@ -0,0 +1,57 @@ +import xmlsec +from tests import base +from xmlsec import constants as consts + +KEY_URL = "pkcs11;pkcs11:token=test;object=test;pin-value=secret1" + + +def setUpModule(): + from tests import softhsm_setup + + softhsm_setup.setup() + + +def tearDownModule(): + from tests import softhsm_setup + + softhsm_setup.teardown() + + +class TestKeys(base.TestMemoryLeaks): + def test_del_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + ctx.key = xmlsec.Key.from_engine(KEY_URL) + del ctx.key + self.assertIsNone(ctx.key) + + def test_set_key(self): + ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) + ctx.key = xmlsec.Key.from_engine(KEY_URL) + self.assertIsNotNone(ctx.key) + + def test_sign_bad_args(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_engine(KEY_URL) + with self.assertRaises(TypeError): + ctx.sign('') + + def test_sign_fail(self): + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_engine(KEY_URL) + with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'): + ctx.sign(self.load_xml('sign1-in.xml')) + + def test_sign_case1(self): + """Should sign a pre-constructed template file using a key from a pkcs11 engine.""" + root = self.load_xml("sign1-in.xml") + sign = xmlsec.tree.find_node(root, consts.NodeSignature) + self.assertIsNotNone(sign) + + ctx = xmlsec.SignatureContext() + ctx.key = xmlsec.Key.from_engine(KEY_URL) + self.assertIsNotNone(ctx.key) + ctx.key.name = 'rsakey.pem' + self.assertEqual("rsakey.pem", ctx.key.name) + + ctx.sign(sign) + self.assertEqual(self.load_xml("sign1-out.xml"), root) From 4f5daea286df89c64fbfc615f422be62b2cdf114 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 11:55:28 +0000 Subject: [PATCH 266/378] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- tests/softhsm_setup.py | 220 +++++++++++++++++++++++++++-------------- 1 file changed, 147 insertions(+), 73 deletions(-) diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index 0a7c37de..432d4b1b 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -45,7 +45,11 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: conf = f.read() msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]' msg = msg.format( - cmd=" ".join(args), code=rv, out=out.strip(), err=err.strip(), conf=conf, + cmd=" ".join(args), + code=rv, + out=out.strip(), + err=err.strip(), + conf=conf, ) raise RuntimeError(msg) return out, err @@ -90,9 +94,7 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: if component_path['SOFTHSM'].endswith('softhsm2-util'): softhsm_version = 2 -openssl_version = subprocess.check_output([component_path['OPENSSL'], - 'version'] - )[8:11].decode() +openssl_version = subprocess.check_output([component_path['OPENSSL'], 'version'])[8:11].decode() p11_test_files: List[str] = [] softhsm_conf: Optional[str] = None @@ -121,27 +123,41 @@ def setup() -> None: with open(softhsm_conf, "w") as f: if softhsm_version == 2: softhsm_db = _temp_dir() - f.write(""" + f.write( + """ # Generated by test directories.tokendir = %s objectstore.backend = file log.level = DEBUG -""" % softhsm_db) +""" + % softhsm_db + ) else: softhsm_db = _temp_file() - f.write(""" + f.write( + """ # Generated by test 0:%s -""" % softhsm_db) +""" + % softhsm_db + ) logging.debug("Initializing the token") - out, err = run_cmd([component_path['SOFTHSM'], - '--slot', '0', - '--label', 'test', - '--init-token', - '--pin', 'secret1', - '--so-pin', 'secret2'], - softhsm_conf=softhsm_conf) + out, err = run_cmd( + [ + component_path['SOFTHSM'], + '--slot', + '0', + '--label', + 'test', + '--init-token', + '--pin', + 'secret1', + '--so-pin', + 'secret2', + ], + softhsm_conf=softhsm_conf, + ) # logging.debug("Generating 1024 bit RSA key in token") # run_cmd([component_path['PKCS11_TOOL'], @@ -155,26 +171,45 @@ def setup() -> None: hash_priv_key = _temp_file() logging.debug("Converting test private key to format for softhsm") - run_cmd([component_path['OPENSSL'], 'pkcs8', - '-topk8', - '-inform', 'PEM', - '-outform', 'PEM', - '-nocrypt', - '-in', os.path.join(DATA_DIR, 'rsakey.pem'), - '-out', hash_priv_key], softhsm_conf=softhsm_conf) + run_cmd( + [ + component_path['OPENSSL'], + 'pkcs8', + '-topk8', + '-inform', + 'PEM', + '-outform', + 'PEM', + '-nocrypt', + '-in', + os.path.join(DATA_DIR, 'rsakey.pem'), + '-out', + hash_priv_key, + ], + softhsm_conf=softhsm_conf, + ) logging.debug("Importing the test key to softhsm") - run_cmd([component_path['SOFTHSM'], - '--import', hash_priv_key, - '--token', 'test', - '--id', 'a1b2', - '--label', 'test', - '--pin', 'secret1'], - softhsm_conf=softhsm_conf) - run_cmd([component_path['PKCS11_TOOL'], - '--module', component_path['P11_MODULE'], - '-l', - '--pin', 'secret1', '-O'], softhsm_conf=softhsm_conf) + run_cmd( + [ + component_path['SOFTHSM'], + '--import', + hash_priv_key, + '--token', + 'test', + '--id', + 'a1b2', + '--label', + 'test', + '--pin', + 'secret1', + ], + softhsm_conf=softhsm_conf, + ) + run_cmd( + [component_path['PKCS11_TOOL'], '--module', component_path['P11_MODULE'], '-l', '--pin', 'secret1', '-O'], + softhsm_conf=softhsm_conf, + ) signer_cert_pem = _temp_file() openssl_conf = _temp_file() logging.debug("Generating OpenSSL config for version {}".format(openssl_version)) @@ -185,21 +220,25 @@ def setup() -> None: # if openssl_version.startswith(b'1.') # else "" # ) - f.write("\n".join([ - "openssl_conf = openssl_def", - "[openssl_def]", - "engines = engine_section", - "[engine_section]", - "pkcs11 = pkcs11_section", - "[req]", - "distinguished_name = req_distinguished_name", - "[req_distinguished_name]", - "[pkcs11_section]", - "engine_id = pkcs11", - # dynamic_path, - "MODULE_PATH = %s" % component_path['P11_MODULE'], - "init = 0", - ])) + f.write( + "\n".join( + [ + "openssl_conf = openssl_def", + "[openssl_def]", + "engines = engine_section", + "[engine_section]", + "pkcs11 = pkcs11_section", + "[req]", + "distinguished_name = req_distinguished_name", + "[req_distinguished_name]", + "[pkcs11_section]", + "engine_id = pkcs11", + # dynamic_path, + "MODULE_PATH = %s" % component_path['P11_MODULE'], + "init = 0", + ] + ) + ) with open(openssl_conf, "r") as f: logging.debug('-------- START DEBUG openssl_conf --------') @@ -213,34 +252,69 @@ def setup() -> None: signer_cert_der = _temp_file() logging.debug("Generating self-signed certificate") - run_cmd([component_path['OPENSSL'], 'req', - '-new', - '-x509', - '-subj', "/CN=Test Signer", - '-engine', 'pkcs11', - '-config', openssl_conf, - '-keyform', 'engine', - '-key', 'label_test', - '-passin', 'pass:secret1', - '-out', signer_cert_pem], softhsm_conf=softhsm_conf) - - run_cmd([component_path['OPENSSL'], 'x509', - '-inform', 'PEM', - '-outform', 'DER', - '-in', signer_cert_pem, - '-out', signer_cert_der], softhsm_conf=softhsm_conf) + run_cmd( + [ + component_path['OPENSSL'], + 'req', + '-new', + '-x509', + '-subj', + "/CN=Test Signer", + '-engine', + 'pkcs11', + '-config', + openssl_conf, + '-keyform', + 'engine', + '-key', + 'label_test', + '-passin', + 'pass:secret1', + '-out', + signer_cert_pem, + ], + softhsm_conf=softhsm_conf, + ) + + run_cmd( + [ + component_path['OPENSSL'], + 'x509', + '-inform', + 'PEM', + '-outform', + 'DER', + '-in', + signer_cert_pem, + '-out', + signer_cert_der, + ], + softhsm_conf=softhsm_conf, + ) logging.debug("Importing certificate into token") - run_cmd([component_path['PKCS11_TOOL'], - '--module', component_path['P11_MODULE'], - '-l', - '--slot-index', '0', - '--id', 'a1b2', - '--label', 'test', - '-y', 'cert', - '-w', signer_cert_der, - '--pin', 'secret1'], softhsm_conf=softhsm_conf) + run_cmd( + [ + component_path['PKCS11_TOOL'], + '--module', + component_path['P11_MODULE'], + '-l', + '--slot-index', + '0', + '--id', + 'a1b2', + '--label', + 'test', + '-y', + 'cert', + '-w', + signer_cert_der, + '--pin', + 'secret1', + ], + softhsm_conf=softhsm_conf, + ) # TODO: Should be teardowned in teardown: os.environ['SOFTHSM_CONF'] = softhsm_conf From 70753591a9b56542961cb1e3b4cd05c92aea7028 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 12 Jun 2023 14:26:51 +0200 Subject: [PATCH 267/378] Remove SOAP The SOAP support fully removed from xmlsec1 library. --- doc/source/modules/constants.rst | 6 - src/constants.c | 2 - src/xmlsec/constants.pyi | 2 - tests/data/enc-bad-in.xml | 208 ------------------------------- tests/test_enc.py | 19 --- 5 files changed, 237 deletions(-) delete mode 100644 tests/data/enc-bad-in.xml diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 4a63fcd7..8127590a 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -166,12 +166,6 @@ Namespaces .. data:: xmlsec.constants.XPointerNs :annotation: = 'http://www.w3.org/2001/04/xmldsig-more/xptr' -.. data:: xmlsec.constants.Soap11Ns - :annotation: = 'http://schemas.xmlsoap.org/soap/envelope/' - -.. data:: xmlsec.constants.Soap12Ns - :annotation: = 'http://www.w3.org/2002/06/soap-envelope' - .. data:: xmlsec.constants.NsExcC14N :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#' diff --git a/src/constants.c b/src/constants.c index 34c81b29..72ae217f 100644 --- a/src/constants.c +++ b/src/constants.c @@ -316,8 +316,6 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_NS_CONSTANT(XPathNs, "XPATH"); PYXMLSEC_ADD_NS_CONSTANT(XPath2Ns, "XPATH2"); PYXMLSEC_ADD_NS_CONSTANT(XPointerNs, "XPOINTER"); - PYXMLSEC_ADD_NS_CONSTANT(Soap11Ns, "SOAP11"); - PYXMLSEC_ADD_NS_CONSTANT(Soap12Ns, "SOAP12"); PYXMLSEC_ADD_NS_CONSTANT(NsExcC14N, "EXC_C14N"); PYXMLSEC_ADD_NS_CONSTANT(NsExcC14NWithComments, "EXC_C14N_WITH_COMMENT"); diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 3430a027..9fd24e53 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -85,8 +85,6 @@ NodeX509Data: Final[str] Ns: Final[str] NsExcC14N: Final[str] NsExcC14NWithComments: Final[str] -Soap11Ns: Final[str] -Soap12Ns: Final[str] TransformAes128Cbc: Final[__Transform] TransformAes128Gcm: Final[__Transform] TransformAes192Cbc: Final[__Transform] diff --git a/tests/data/enc-bad-in.xml b/tests/data/enc-bad-in.xml deleted file mode 100644 index 460738fc..00000000 --- a/tests/data/enc-bad-in.xml +++ /dev/null @@ -1,208 +0,0 @@ - - - - - - - - - MyNextCar - CreditApplication - MYNEXTCAR - VW - 409D03 - MyNextCar - - 2018-11-20T09:37:45Z - 7f0842cc-8d47-4955-be31-c61d07ee490b - - VW - - - - - - -
- VCI_MNA_0000070250 - - - Car Chantilly -
- 14839 Stonecroft Center Ct - Chantilly - VA - US - 20151 -
- - - MyNextCar - MNA - - 7039562100 - - CAR -
- N -
- - - 2017 - Q7 - CAR - New - 0 - Prestige - - 64300.0 - MSRP - - - 64300.0 - Selling Price - - - - - 113456789 - NationalId - - - John - Q - Public - -
- 999 Washington Ave - Apt #332 - Front Royal - VA - US - 22630 - 01 - 10 - Own -
-
- 21 E 9th Ave - Boulder - CO - US - 80301-7577 - 07 - 11 - Own -
- - 3032852402 - 3032852405 - 7203554444 - JohnQPublic@anydomain.org - - - 1967-07-31 - - 0 - - UPS -
- 1775 Wiehle Ave. - Reston - VA - US - 20190 -
- 9500.0 - Driver - 01 - 05 - Current -
- - FedEx - 4000.00 - Driver - 04 - 09 - Previous - - 1252.52 - - 1500.00 - - - 1 - Consents to Credit Check - -
- - - 123435325 - NationalId - - - Lisa - C - Public - -
- 999 Lewis Street - Front Royal - VA - US - 22630 - 5 - 0 - Own -
- - 5401110000 - 5401110073 - public@test.com - - - 1963-04-20 - - - Christendom College -
- 999 Christendom Dr - Front Royal - VA - US - 22630 -
- 6200.00 - Professor - 5 - 0 - Current -
- 1252.52 - - 1 - Consents to Credit Check - -
- - R - 0.00 - 66 - 5000.00 - INDIVCOAPP - 2000.00 - MyNextCar - - 1978 - Bonneville - Pontiac - Coupe - - -
-
-
-
-
-
diff --git a/tests/test_enc.py b/tests/test_enc.py index 63e00169..1788b4d6 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -233,22 +233,3 @@ def test_decrypt_bad_args(self): ctx = xmlsec.EncryptionContext() with self.assertRaises(TypeError): ctx.decrypt('') - - def check_no_segfault(self): - namespaces = {'soap': 'http://schemas.xmlsoap.org/soap/envelope/'} - - manager = xmlsec.KeysManager() - key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) - manager.add_key(key) - template = self.load_xml('enc-bad-in.xml') - enc_data = xmlsec.template.encrypted_data_create( - template, xmlsec.Transform.AES128, type=xmlsec.EncryptionType.CONTENT, ns='xenc' - ) - xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') - enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.Transform.RSA_PKCS1) - xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) - data = template.find('soap:Body', namespaces=namespaces) - enc_ctx = xmlsec.EncryptionContext(manager) - enc_ctx.key = xmlsec.Key.generate(xmlsec.KeyData.AES, 192, xmlsec.KeyDataType.SESSION) - self.assertRaises(Exception, enc_ctx.encrypt_xml(enc_data, data)) From 2c26131e2d965346b538d86349fe121027afd9f4 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 12 Jun 2023 15:12:57 +0200 Subject: [PATCH 268/378] Upgrade isort because of poetry dependency issue Fix https://github.com/PyCQA/isort/issues/2077 --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0545b12f..bf877f39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy From b865569c84ff00f116b321527a2bd381321c9402 Mon Sep 17 00:00:00 2001 From: Konstantin Demin Date: Thu, 24 Aug 2023 00:29:17 +0300 Subject: [PATCH 269/378] setup: better deal with compiler flags - honor environment variable PYXMLSEC_OPTIMIZE_SIZE to switch between speed and size optimization - enabled by default for backward compatibility - better deal with compiler flags for different platforms Signed-off-by: Konstantin Demin --- setup.py | 14 +++++++++++--- 1 file changed, 11 insertions(+), 3 deletions(-) diff --git a/setup.py b/setup.py index 9a3c9277..c0fd0f7d 100644 --- a/setup.py +++ b/setup.py @@ -86,6 +86,7 @@ def run(self): ext = self.ext_map['xmlsec'] self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) + self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True) if self.static or sys.platform == 'win32': self.info('starting static build on {}'.format(sys.platform)) @@ -153,11 +154,18 @@ def run(self): ) if self.debug: - ext.extra_compile_args.append('-Wall') - ext.extra_compile_args.append('-O0') ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) + if sys.platform == 'win32': + ext.extra_compile_args.append('/Od') + else: + ext.extra_compile_args.append('-Wall') + ext.extra_compile_args.append('-O0') else: - ext.extra_compile_args.append('-Os') + if self.size_opt: + if sys.platform == 'win32': + ext.extra_compile_args.append('/Os') + else: + ext.extra_compile_args.append('-Os') super(build_ext, self).run() From 5f57f2eac756df213e83a2fdb452057909e2dd21 Mon Sep 17 00:00:00 2001 From: David Adamec Date: Fri, 15 Sep 2023 17:49:15 -0700 Subject: [PATCH 270/378] Add compatibility for xmlsec 1.3 --- doc/source/modules/constants.rst | 6 ------ src/constants.c | 2 -- src/enc.c | 7 +++++++ src/xmlsec/constants.pyi | 2 -- 4 files changed, 7 insertions(+), 10 deletions(-) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 4a63fcd7..8127590a 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -166,12 +166,6 @@ Namespaces .. data:: xmlsec.constants.XPointerNs :annotation: = 'http://www.w3.org/2001/04/xmldsig-more/xptr' -.. data:: xmlsec.constants.Soap11Ns - :annotation: = 'http://schemas.xmlsoap.org/soap/envelope/' - -.. data:: xmlsec.constants.Soap12Ns - :annotation: = 'http://www.w3.org/2002/06/soap-envelope' - .. data:: xmlsec.constants.NsExcC14N :annotation: = 'http://www.w3.org/2001/10/xml-exc-c14n#' diff --git a/src/constants.c b/src/constants.c index 34c81b29..72ae217f 100644 --- a/src/constants.c +++ b/src/constants.c @@ -316,8 +316,6 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_NS_CONSTANT(XPathNs, "XPATH"); PYXMLSEC_ADD_NS_CONSTANT(XPath2Ns, "XPATH2"); PYXMLSEC_ADD_NS_CONSTANT(XPointerNs, "XPOINTER"); - PYXMLSEC_ADD_NS_CONSTANT(Soap11Ns, "SOAP11"); - PYXMLSEC_ADD_NS_CONSTANT(Soap12Ns, "SOAP12"); PYXMLSEC_ADD_NS_CONSTANT(NsExcC14N, "EXC_C14N"); PYXMLSEC_ADD_NS_CONSTANT(NsExcC14NWithComments, "EXC_C14N_WITH_COMMENT"); diff --git a/src/enc.c b/src/enc.c index aaf35ae5..475cd2d4 100644 --- a/src/enc.c +++ b/src/enc.c @@ -50,6 +50,13 @@ static int PyXmlSec_EncryptionContext__init__(PyObject* self, PyObject* args, Py } ctx->manager = manager; PYXMLSEC_DEBUGF("%p: init enc context - ok, manager - %p", self, manager); + + // xmlsec 1.3 changed the key search to strict mode, causing various examples + // in the docs to fail. For backwards compatibility, this changes it back to + // lax mode for now. + ctx->handle->keyInfoReadCtx.flags = XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH; + ctx->handle->keyInfoWriteCtx.flags = XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH; + return 0; ON_FAIL: PYXMLSEC_DEBUGF("%p: init enc context - failed", self); diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 3430a027..9fd24e53 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -85,8 +85,6 @@ NodeX509Data: Final[str] Ns: Final[str] NsExcC14N: Final[str] NsExcC14NWithComments: Final[str] -Soap11Ns: Final[str] -Soap12Ns: Final[str] TransformAes128Cbc: Final[__Transform] TransformAes128Gcm: Final[__Transform] TransformAes192Cbc: Final[__Transform] From 0e7c5e718e8d221331b0a5f851094a5b4181eeae Mon Sep 17 00:00:00 2001 From: David Adamec Date: Fri, 15 Sep 2023 18:07:07 -0700 Subject: [PATCH 271/378] fix 1.2 compatibility --- src/enc.c | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/enc.c b/src/enc.c index 475cd2d4..5453ef99 100644 --- a/src/enc.c +++ b/src/enc.c @@ -17,6 +17,11 @@ #include #include +// Backwards compatibility with xmlsec 1.2 +#ifndef XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH +#define XMLSEC_KEYINFO_FLAGS_LAX_KEY_SEARCH 0x00008000 +#endif + typedef struct { PyObject_HEAD xmlSecEncCtxPtr handle; From 40c14c45a352f2812e796a071ef7d12f5a70be58 Mon Sep 17 00:00:00 2001 From: David Adamec Date: Fri, 15 Sep 2023 19:40:04 -0700 Subject: [PATCH 272/378] update isort to fix poetry error in pre-commit --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0545b12f..bf877f39 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.10.1 + rev: 5.12.0 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy From f2617835b9c0dc8740caa89e7aa765e3d5afe445 Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Thu, 12 Oct 2023 18:09:38 +0100 Subject: [PATCH 273/378] Don't define `MODULE_NAME` as a string literal The `MODULE_NAME` macro is used in contexts where a string literal is not valid, but the fallback value set in `src/common.h` defines it as such; this differs from how it is defined in `setup.py`. Define `MODULE_NAME` in `src/common.h` as it is defined in `setup.py`. Fixes #267. --- src/common.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/common.h b/src/common.h index 243ed651..a6176551 100644 --- a/src/common.h +++ b/src/common.h @@ -13,7 +13,7 @@ #include "debug.h" #ifndef MODULE_NAME -#define MODULE_NAME "xmlsec" +#define MODULE_NAME xmlsec #endif #define JOIN(X,Y) DO_JOIN1(X,Y) From c97f2b8ddc7b30de73411bdfbeb9903899ee1495 Mon Sep 17 00:00:00 2001 From: Chris Novakovic Date: Fri, 13 Oct 2023 10:53:48 +0100 Subject: [PATCH 274/378] Make DES/3DES/KW-3DES support conditional on DES availability in XMLSec Some TLS libraries (e.g. OpenSSL) can be built without support for DES and DES-derived algorithms. Rather than assuming that xmlsec always supports them, guard the declaration of the DES, 3DES and KW-3DES constants based on the value of `XMLSEC_NO_DES`. Fixes #269. --- src/constants.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/constants.c b/src/constants.c index 34c81b29..d797086d 100644 --- a/src/constants.c +++ b/src/constants.c @@ -441,7 +441,9 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataRetrievalMethod, "RETRIEVALMETHOD") PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEncryptedKey, "ENCRYPTEDKEY") PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataAes, "AES") +#ifndef XMLSEC_NO_DES PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDes, "DES") +#endif #ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDsa, "DSA") #endif @@ -489,8 +491,10 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWAes192, "KW_AES192"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWAes256, "KW_AES256"); +#ifndef XMLSEC_NO_DES PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDes3Cbc, "DES3"); PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformKWDes3, "KW_DES3"); +#endif #ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_TRANSFORM_CONSTANT(TransformDsaSha1, "DSA_SHA1"); #endif From 31bea7c0d2694150818f9d901682aa1fe84449ac Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Sat, 13 Jan 2024 19:40:05 -0500 Subject: [PATCH 275/378] Use KeyDataEc rather than deprecated KeyDataEcdsa --- doc/source/modules/constants.rst | 2 +- src/constants.c | 2 +- src/xmlsec/constants.pyi | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 8127590a..8fdac118 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -47,7 +47,7 @@ KeyData The DSA key klass. -.. data:: xmlsec.constants.KeyDataEcdsa +.. data:: xmlsec.constants.KeyDataEc The ECDSA key klass. diff --git a/src/constants.c b/src/constants.c index e3b64527..f2c5a636 100644 --- a/src/constants.c +++ b/src/constants.c @@ -447,7 +447,7 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #endif #if XMLSEC_VERSION_HEX > 0x10212 // from version 1.2.19 - PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEcdsa, "ECDSA") + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEc, "ECDSA") #endif PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataHmac, "HMAC") PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataRsa, "RSA") diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 9fd24e53..80afdd22 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -29,7 +29,7 @@ EncNs: Final[str] KeyDataAes: Final[__KeyData] KeyDataDes: Final[__KeyData] KeyDataDsa: Final[__KeyData] -KeyDataEcdsa: Final[__KeyData] +KeyDataEc: Final[__KeyData] KeyDataEncryptedKey: Final[__KeyData] KeyDataFormatBinary: Final[int] KeyDataFormatCertDer: Final[int] From 7891e715a7c343a1fd52c86a5085a1d1cc62e711 Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Sat, 13 Jan 2024 19:40:28 -0500 Subject: [PATCH 276/378] Use xmlSecCryptoAppKeyLoadEx instead of deprecated xmlSecCryptoAppKeyLoad --- src/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.c b/src/keys.c index 1362b128..47678a53 100644 --- a/src/keys.c +++ b/src/keys.c @@ -163,7 +163,7 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* if (is_content) { key->handle = xmlSecCryptoAppKeyLoadMemory((const xmlSecByte*)data, (xmlSecSize)data_size, format, password, NULL, NULL); } else { - key->handle = xmlSecCryptoAppKeyLoad(data, format, password, NULL, NULL); + key->handle = xmlSecCryptoAppKeyLoadEx(data, xmlSecKeyDataTypePrivate, format, password, NULL, NULL); } Py_END_ALLOW_THREADS; From c9c660b8f336a8501ab655b9f59a993378b5f38b Mon Sep 17 00:00:00 2001 From: Antoine Martin Date: Tue, 12 Mar 2024 19:51:08 -0400 Subject: [PATCH 277/378] Use xmlSecCryptoAppKeyLoadEx instead of xmlSecCryptoAppKeyLoad for pkcs11 support --- src/keys.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/keys.c b/src/keys.c index a8ffde25..8b84c343 100644 --- a/src/keys.c +++ b/src/keys.c @@ -206,7 +206,7 @@ static PyObject* PyXmlSec_KeyFromEngine(PyObject* self, PyObject* args, PyObject if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; Py_BEGIN_ALLOW_THREADS; - key->handle = xmlSecCryptoAppKeyLoad(engine_and_key_id, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), + key->handle = xmlSecCryptoAppKeyLoadEx(engine_and_key_id, xmlSecKeyDataTypePrivate, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), (void*)engine_and_key_id); Py_END_ALLOW_THREADS; From 595aeaa2651ba0a1f80565ceac7550fd1abd38fe Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Wed, 13 Mar 2024 16:46:55 +0100 Subject: [PATCH 278/378] Make the library backward compatible Starting from version xmlsec1-1.3.3, some of the constant and keys that were deprecated, removed from the library entirely. This change would add version awareness and backward compatible. --- doc/source/modules/constants.rst | 6 +++++- src/constants.c | 7 +++++-- src/keys.c | 15 ++++++++++++--- src/xmlsec/constants.pyi | 1 + 4 files changed, 23 insertions(+), 6 deletions(-) diff --git a/doc/source/modules/constants.rst b/doc/source/modules/constants.rst index 8fdac118..3df6b50f 100644 --- a/doc/source/modules/constants.rst +++ b/doc/source/modules/constants.rst @@ -47,9 +47,13 @@ KeyData The DSA key klass. +.. data:: xmlsec.constants.KeyDataEcdsa + + (Deprecated. The EC key klass) The ECDSA key klass. + .. data:: xmlsec.constants.KeyDataEc - The ECDSA key klass. + The EC key klass. .. data:: xmlsec.constants.KeyDataHmac diff --git a/src/constants.c b/src/constants.c index f2c5a636..bd1fa5e0 100644 --- a/src/constants.c +++ b/src/constants.c @@ -445,8 +445,11 @@ int PyXmlSec_ConstantsModule_Init(PyObject* package) { #ifndef XMLSEC_NO_DSA PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataDsa, "DSA") #endif -#if XMLSEC_VERSION_HEX > 0x10212 - // from version 1.2.19 +#if XMLSEC_VERSION_HEX > 0x10212 && XMLSEC_VERSION_HEX < 0x10303 + // from version 1.2.19 to version 1.3.2 (inclusive) + PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEcdsa, "ECDSA") +#elif XMLSEC_VERSION_HEX >= 0x10303 + // from version 1.3.3 (inclusive) PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataEc, "ECDSA") #endif PYXMLSEC_ADD_KEYDATA_CONSTANT(KeyDataHmac, "HMAC") diff --git a/src/keys.c b/src/keys.c index 8b84c343..5ff04aae 100644 --- a/src/keys.c +++ b/src/keys.c @@ -163,7 +163,12 @@ static PyObject* PyXmlSec_KeyFromFile(PyObject* self, PyObject* args, PyObject* if (is_content) { key->handle = xmlSecCryptoAppKeyLoadMemory((const xmlSecByte*)data, (xmlSecSize)data_size, format, password, NULL, NULL); } else { - key->handle = xmlSecCryptoAppKeyLoadEx(data, xmlSecKeyDataTypePrivate, format, password, NULL, NULL); + #if XMLSEC_VERSION_HEX >= 0x10303 + // from version 1.3.3 (inclusive) + key->handle = xmlSecCryptoAppKeyLoadEx(data, xmlSecKeyDataTypePrivate, format, password, NULL, NULL); + #else + key->handle = xmlSecCryptoAppKeyLoad(data, format, password, NULL, NULL); + #endif } Py_END_ALLOW_THREADS; @@ -206,8 +211,12 @@ static PyObject* PyXmlSec_KeyFromEngine(PyObject* self, PyObject* args, PyObject if ((key = PyXmlSec_NewKey1((PyTypeObject*)self)) == NULL) goto ON_FAIL; Py_BEGIN_ALLOW_THREADS; - key->handle = xmlSecCryptoAppKeyLoadEx(engine_and_key_id, xmlSecKeyDataTypePrivate, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), - (void*)engine_and_key_id); + #if XMLSEC_VERSION_HEX >= 0x10303 + // from version 1.3.3 (inclusive) + key->handle = xmlSecCryptoAppKeyLoadEx(engine_and_key_id, xmlSecKeyDataTypePrivate, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), (void*)engine_and_key_id); + #else + key->handle = xmlSecCryptoAppKeyLoad(engine_and_key_id, xmlSecKeyDataFormatEngine, NULL, xmlSecCryptoAppGetDefaultPwdCallback(), (void*)engine_and_key_id); + #endif Py_END_ALLOW_THREADS; if (key->handle == NULL) { diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 80afdd22..3c3ea94f 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -30,6 +30,7 @@ KeyDataAes: Final[__KeyData] KeyDataDes: Final[__KeyData] KeyDataDsa: Final[__KeyData] KeyDataEc: Final[__KeyData] +KeyDataEcdsa: Final[__KeyData] KeyDataEncryptedKey: Final[__KeyData] KeyDataFormatBinary: Final[int] KeyDataFormatCertDer: Final[int] From 802dff28340d9031d694ad77825a7333dc98ef93 Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Wed, 13 Mar 2024 16:17:34 -0400 Subject: [PATCH 279/378] Update correct URL: No func change --- README.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.rst b/README.rst index e1924652..60fb3ea1 100644 --- a/README.rst +++ b/README.rst @@ -136,7 +136,7 @@ Building from source .. code-block:: bash - git clone https://github.com/mehcode/python-xmlsec.git + git clone https://github.com/xmlsec/python-xmlsec.git #. Change into the ``python-xmlsec`` root directory. From 0bad2e462da4ea912c7a258334d0bcb3e0c5aa86 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 17 Mar 2024 13:25:15 -0300 Subject: [PATCH 280/378] Add ability to query libxml version number --- src/main.c | 15 ++++++++++++++- src/platform.h | 7 +++++++ 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/src/main.c b/src/main.c index 5773db3b..0ee5e2cd 100644 --- a/src/main.c +++ b/src/main.c @@ -121,11 +121,18 @@ static PyObject* PyXmlSec_PyShutdown(PyObject* self) { static char PyXmlSec_GetLibXmlSecVersion__doc__[] = \ "get_libxmlsec_version() -> tuple\n" - "Returns Version tuple of wrapped libxml library."; + "Returns Version tuple of wrapped libxmlsec library."; static PyObject* PyXmlSec_GetLibXmlSecVersion() { return Py_BuildValue("(iii)", XMLSEC_VERSION_MAJOR, XMLSEC_VERSION_MINOR, XMLSEC_VERSION_SUBMINOR); } +static char PyXmlSec_GetLibXmlVersion__doc__[] = \ + "get_libxml_version() -> tuple\n" + "Returns Version tuple of wrapped libxml library."; +static PyObject* PyXmlSec_GetLibXmlVersion() { + return Py_BuildValue("(iii)", XMLSEC_LIBXML_VERSION_MAJOR, XMLSEC_LIBXML_VERSION_MINOR, XMLSEC_LIBXML_VERSION_PATCH); +} + static char PyXmlSec_PyEnableDebugOutput__doc__[] = \ "enable_debug_trace(enabled) -> None\n" "Enables or disables calling LibXML2 callback from the default errors callback.\n\n" @@ -399,6 +406,12 @@ static PyMethodDef PyXmlSec_MainMethods[] = { METH_NOARGS, PyXmlSec_GetLibXmlSecVersion__doc__ }, + { + "get_libxml_version", + (PyCFunction)PyXmlSec_GetLibXmlVersion, + METH_NOARGS, + PyXmlSec_GetLibXmlVersion__doc__ + }, { "enable_debug_trace", (PyCFunction)PyXmlSec_PyEnableDebugOutput, diff --git a/src/platform.h b/src/platform.h index 35163e88..1fc82b7b 100644 --- a/src/platform.h +++ b/src/platform.h @@ -12,6 +12,7 @@ #define PY_SSIZE_T_CLEAN 1 +#include #include #include @@ -19,6 +20,12 @@ #include #endif /* MS_WIN32 */ +#define XMLSEC_EXTRACT_VERSION(x, y) ((x / (y)) % 100) + +#define XMLSEC_LIBXML_VERSION_MAJOR XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 100 * 100) +#define XMLSEC_LIBXML_VERSION_MINOR XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 100) +#define XMLSEC_LIBXML_VERSION_PATCH XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 1) + #define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 16) | (XMLSEC_VERSION_MINOR << 8) | (XMLSEC_VERSION_SUBMINOR)) // XKMS support was removed in version 1.2.21 From 01b18c9a09ee54a3d78c8da039777de8512d7380 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 20:35:34 -0300 Subject: [PATCH 281/378] Set enable-md5 when doing static build for libxmlsec1 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 489844c8..277a8892 100644 --- a/setup.py +++ b/setup.py @@ -437,6 +437,7 @@ def prepare_static_build_linux(self): prefix_arg, '--disable-shared', '--disable-gost', + '--enable-md5', '--disable-crypto-dl', '--enable-static=yes', '--enable-shared=no', From 2a717dd3987ba9538617874aba36e4f8326f514e Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 21:25:01 -0300 Subject: [PATCH 282/378] Fix sdist workflow --- .github/workflows/sdist.yml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 6ca7a657..e7c0f39d 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -18,8 +18,7 @@ jobs: - name: Install test dependencies run: | sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl - pip install --upgrade -r requirements-test.txt - pip install black # for stub generation tests + pip install --upgrade -r requirements-test.txt --no-binary lxml pip install dist/xmlsec-$(python setup.py --version).tar.gz - name: Run tests run: | From e8ff43b50faf940637d0627b7de2f4566f0dfe3d Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 22:05:04 -0300 Subject: [PATCH 283/378] Fix macos workflow --- .github/workflows/macosx.yml | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 24fa6ddd..2c974831 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -19,8 +19,9 @@ jobs: - name: Build macosx_x86_64 wheel env: CC: clang - CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" - LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping -I/usr/local/opt/libxml2/include" + LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping -L/usr/local/opt/libxml2/lib" + PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" run: | python -m build rm -rf build/ @@ -31,9 +32,13 @@ jobs: echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV - name: Install test dependencies run: | - pip install coverage --upgrade -r requirements-test.txt + pip install coverage --upgrade -r requirements-test.txt --no-binary lxml pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV + env: + CFLAGS: "-I/usr/local/opt/libxml2/include" + LDFLAGS: "-L/usr/local/opt/libxml2/lib" + PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" - name: Run tests run: | coverage run -m pytest -v --color=yes From 5c2cbd59b936bc5fe8563c4cfa9a1b350b5fae3f Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 21 Mar 2024 09:08:36 -0300 Subject: [PATCH 284/378] Add arch flag --- .github/workflows/macosx.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 2c974831..39fc37de 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -36,6 +36,7 @@ jobs: pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV env: + CC: clang CFLAGS: "-I/usr/local/opt/libxml2/include" LDFLAGS: "-L/usr/local/opt/libxml2/lib" PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" @@ -45,5 +46,5 @@ jobs: - name: Report coverage to codecov run: | /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata - /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} -instr-profile=pyxmlsec.profdata src > coverage.txt + /Library/Developer/CommandLineTools/usr/bin/llvm-cov -arch x86_64 show ${{ env.PYXMLSEC_LIBFILE }} -instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt From ad0b27d3ac3f1d89b4641dfdc1482d54d9dd20a1 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 21 Mar 2024 09:13:53 -0300 Subject: [PATCH 285/378] No need to install lxml from source, brew libxml2 version matches --- .github/workflows/macosx.yml | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 39fc37de..129c4e89 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -32,14 +32,9 @@ jobs: echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV - name: Install test dependencies run: | - pip install coverage --upgrade -r requirements-test.txt --no-binary lxml + pip install coverage --upgrade -r requirements-test.txt pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV - env: - CC: clang - CFLAGS: "-I/usr/local/opt/libxml2/include" - LDFLAGS: "-L/usr/local/opt/libxml2/lib" - PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" - name: Run tests run: | coverage run -m pytest -v --color=yes From 4bd490143932efaaf41f25ea3b3f3866cbe50554 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 21 Mar 2024 09:16:54 -0300 Subject: [PATCH 286/378] fix arch flag --- .github/workflows/macosx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 129c4e89..2bc44c1e 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -41,5 +41,5 @@ jobs: - name: Report coverage to codecov run: | /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata - /Library/Developer/CommandLineTools/usr/bin/llvm-cov -arch x86_64 show ${{ env.PYXMLSEC_LIBFILE }} -instr-profile=pyxmlsec.profdata src > coverage.txt + /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=x86_64 --instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt From 869beeb281cc1366a63e29f7145c62082fbacbef Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 21:28:25 -0300 Subject: [PATCH 287/378] Fix manylinux build --- .github/workflows/manylinux.yml | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 520e5ba6..6d2dbb1a 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -7,14 +7,7 @@ jobs: matrix: python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] image: - - manylinux2010_x86_64 - - manylinux_2_24_x86_64 - - musllinux_1_1_x86_64 - exclude: - - image: manylinux2010_x86_64 - python-abi: cp311-cp311 - - image: manylinux2010_i686 - python-abi: cp311-cp311 + - manylinux2014_x86_64 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 From 5794266cff235c0788842c49815408ed35f04e06 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 21 Mar 2024 11:19:59 -0300 Subject: [PATCH 288/378] Try just setting pkg_config_path. --- .github/workflows/macosx.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 2bc44c1e..e2a04057 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -19,8 +19,8 @@ jobs: - name: Build macosx_x86_64 wheel env: CC: clang - CFLAGS: "-fprofile-instr-generate -fcoverage-mapping -I/usr/local/opt/libxml2/include" - LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping -L/usr/local/opt/libxml2/lib" + CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" + LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" run: | python -m build From ee9fbd03ac4c466447f0f67e3032866657dcb19d Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 21 Mar 2024 20:52:49 -0300 Subject: [PATCH 289/378] Version check when setting up lxml - Expose both the compiled version and the linked version of libxml2 - Do a check that the versions match when initializing the module. Otherwise raise an exception. This seems like a better result then a difficult to diagnose segfault. --- src/lxml.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ src/lxml.h | 9 +++++ src/main.c | 30 ++++++++++++++-- src/platform.h | 7 ---- 4 files changed, 131 insertions(+), 10 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index aa1abae0..bb7e6a96 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -9,6 +9,7 @@ #include "common.h" #include "lxml.h" +#include "exception.h" #include #include @@ -17,8 +18,102 @@ #include #include +#define XMLSEC_EXTRACT_VERSION(x, y) ((x / (y)) % 100) + +#define XMLSEC_EXTRACT_MAJOR(x) XMLSEC_EXTRACT_VERSION(x, 100 * 100) +#define XMLSEC_EXTRACT_MINOR(x) XMLSEC_EXTRACT_VERSION(x, 100) +#define XMLSEC_EXTRACT_PATCH(x) XMLSEC_EXTRACT_VERSION(x, 1) + +static long PyXmlSec_GetLibXmlVersionLong() { + return PyOS_strtol(xmlParserVersion, NULL, 10); +} +long PyXmlSec_GetLibXmlVersionMajor() { + return XMLSEC_EXTRACT_MAJOR(PyXmlSec_GetLibXmlVersionLong()); +} +long PyXmlSec_GetLibXmlVersionMinor() { + return XMLSEC_EXTRACT_MINOR(PyXmlSec_GetLibXmlVersionLong()); +} +long PyXmlSec_GetLibXmlVersionPatch() { + return XMLSEC_EXTRACT_PATCH(PyXmlSec_GetLibXmlVersionLong()); +} + +long PyXmlSec_GetLibXmlCompiledVersionMajor() { + return XMLSEC_EXTRACT_MAJOR(LIBXML_VERSION); +} +long PyXmlSec_GetLibXmlCompiledVersionMinor() { + return XMLSEC_EXTRACT_MINOR(LIBXML_VERSION); +} +long PyXmlSec_GetLibXmlCompiledVersionPatch() { + return XMLSEC_EXTRACT_PATCH(LIBXML_VERSION); +} + +static int PyXmlSec_CheckLibXmlLibraryVersion(void) { + // Make sure that the version of libxml2 that we were compiled against is the same as the one + // that is loaded. If there is a version mismatch, we could run into segfaults. + + if (PyXmlSec_GetLibXmlVersionMajor() != PyXmlSec_GetLibXmlCompiledVersionMajor() || + PyXmlSec_GetLibXmlVersionMinor() != PyXmlSec_GetLibXmlCompiledVersionMinor()) { + return -1; + } + + return 0; +} + +static int PyXmlSec_CheckLxmlLibraryVersion(void) { + // Make sure that the version of libxml2 lxml is using is the same as the one we are using. Because + // we pass trees between the two libraries, we need to make sure that they are using the same version + // of libxml2, or we could run into difficult to debug segfaults. + // See: https://github.com/xmlsec/python-xmlsec/issues/283 + + PyObject* lxml = NULL; + PyObject* version = NULL; + + // Default to failure + int result = -1; + + lxml = PyImport_ImportModule("lxml.etree"); + if (lxml == NULL) { + goto FINALIZE; + } + version = PyObject_GetAttrString(lxml, "LIBXML_VERSION"); + if (version == NULL) { + goto FINALIZE; + } + if (!PyTuple_Check(version) || PyTuple_Size(version) != 3) { + goto FINALIZE; + } + + PyObject* major = PyTuple_GetItem(version, 0); + PyObject* minor = PyTuple_GetItem(version, 1); + + if (!PyLong_Check(major) || !PyLong_Check(minor)) { + goto FINALIZE; + } + + if (PyLong_AsLong(major) != PyXmlSec_GetLibXmlVersionMajor() || PyLong_AsLong(minor) != PyXmlSec_GetLibXmlVersionMinor()) { + goto FINALIZE; + } + + result = 0; + +FINALIZE: + // Cleanup our references, and return the result + Py_XDECREF(lxml); + Py_XDECREF(version); + return result; +} int PyXmlSec_InitLxmlModule(void) { + if (PyXmlSec_CheckLibXmlLibraryVersion() < 0) { + PyXmlSec_SetLastError("xmlsec libxml2 library compiled version vs runtime version mismatch"); + return -1; + } + + if (PyXmlSec_CheckLxmlLibraryVersion() < 0) { + PyXmlSec_SetLastError("lxml & xmlsec libxml2 library version mismatch"); + return -1; + } + return import_lxml__etree(); } diff --git a/src/lxml.h b/src/lxml.h index 6824076b..72050efe 100644 --- a/src/lxml.h +++ b/src/lxml.h @@ -29,4 +29,13 @@ PyXmlSec_LxmlElementPtr PyXmlSec_elementFactory(PyXmlSec_LxmlDocumentPtr doc, xm // converts o to PyObject, None object is not allowed, does not increment ref_counts int PyXmlSec_LxmlElementConverter(PyObject* o, PyXmlSec_LxmlElementPtr* p); +// get version numbers for libxml2 both compiled and loaded +long PyXmlSec_GetLibXmlVersionMajor(); +long PyXmlSec_GetLibXmlVersionMinor(); +long PyXmlSec_GetLibXmlVersionPatch(); + +long PyXmlSec_GetLibXmlCompiledVersionMajor(); +long PyXmlSec_GetLibXmlCompiledVersionMinor(); +long PyXmlSec_GetLibXmlCompiledVersionPatch(); + #endif // __PYXMLSEC_LXML_H__ diff --git a/src/main.c b/src/main.c index 0ee5e2cd..61eac139 100644 --- a/src/main.c +++ b/src/main.c @@ -10,6 +10,7 @@ #include "common.h" #include "platform.h" #include "exception.h" +#include "lxml.h" #include #include @@ -127,10 +128,27 @@ static PyObject* PyXmlSec_GetLibXmlSecVersion() { } static char PyXmlSec_GetLibXmlVersion__doc__[] = \ - "get_libxml_version() -> tuple\n" - "Returns Version tuple of wrapped libxml library."; + "get_libxml_version() -> tuple[int, int, int]\n" + "Returns version tuple of libxml2 library xmlsec is using."; static PyObject* PyXmlSec_GetLibXmlVersion() { - return Py_BuildValue("(iii)", XMLSEC_LIBXML_VERSION_MAJOR, XMLSEC_LIBXML_VERSION_MINOR, XMLSEC_LIBXML_VERSION_PATCH); + return Py_BuildValue( + "(iii)", + PyXmlSec_GetLibXmlVersionMajor(), + PyXmlSec_GetLibXmlVersionMinor(), + PyXmlSec_GetLibXmlVersionPatch() + ); +} + +static char PyXmlSec_GetLibXmlCompiledVersion__doc__[] = \ + "get_libxml_compiled_version() -> tuple[int, int, int]\n" + "Returns version tuple of libxml2 library xmlsec was compiled with."; +static PyObject* PyXmlSec_GetLibXmlCompiledVersion() { + return Py_BuildValue( + "(iii)", + PyXmlSec_GetLibXmlCompiledVersionMajor(), + PyXmlSec_GetLibXmlCompiledVersionMinor(), + PyXmlSec_GetLibXmlCompiledVersionPatch() + ); } static char PyXmlSec_PyEnableDebugOutput__doc__[] = \ @@ -412,6 +430,12 @@ static PyMethodDef PyXmlSec_MainMethods[] = { METH_NOARGS, PyXmlSec_GetLibXmlVersion__doc__ }, + { + "get_libxml_compiled_version", + (PyCFunction)PyXmlSec_GetLibXmlCompiledVersion, + METH_NOARGS, + PyXmlSec_GetLibXmlCompiledVersion__doc__ + }, { "enable_debug_trace", (PyCFunction)PyXmlSec_PyEnableDebugOutput, diff --git a/src/platform.h b/src/platform.h index 1fc82b7b..35163e88 100644 --- a/src/platform.h +++ b/src/platform.h @@ -12,7 +12,6 @@ #define PY_SSIZE_T_CLEAN 1 -#include #include #include @@ -20,12 +19,6 @@ #include #endif /* MS_WIN32 */ -#define XMLSEC_EXTRACT_VERSION(x, y) ((x / (y)) % 100) - -#define XMLSEC_LIBXML_VERSION_MAJOR XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 100 * 100) -#define XMLSEC_LIBXML_VERSION_MINOR XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 100) -#define XMLSEC_LIBXML_VERSION_PATCH XMLSEC_EXTRACT_VERSION(LIBXML_VERSION, 1) - #define XMLSEC_VERSION_HEX ((XMLSEC_VERSION_MAJOR << 16) | (XMLSEC_VERSION_MINOR << 8) | (XMLSEC_VERSION_SUBMINOR)) // XKMS support was removed in version 1.2.21 From d8d6c6266a1a9c3deed4a8b809325c6549c84530 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 24 Mar 2024 19:45:23 -0300 Subject: [PATCH 290/378] Update .github/workflows/macosx.yml Co-authored-by: Stu Tomlinson --- .github/workflows/macosx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index e2a04057..f1bfb7d0 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -21,7 +21,7 @@ jobs: CC: clang CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" - PKG_CONFIG_PATH: "/usr/local/opt/libxml2/lib/pkgconfig" + PKG_CONFIG_PATH: "$(brew --prefix)/opt/libxml2/lib/pkgconfig" run: | python -m build rm -rf build/ From d84f015f6aa4a6b058c4b0ef5ca9044f39b512f8 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 24 Mar 2024 19:45:32 -0300 Subject: [PATCH 291/378] Update .github/workflows/macosx.yml Co-authored-by: Stu Tomlinson --- .github/workflows/macosx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index f1bfb7d0..9b5149c1 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -41,5 +41,5 @@ jobs: - name: Report coverage to codecov run: | /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata - /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=x86_64 --instr-profile=pyxmlsec.profdata src > coverage.txt + /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=$(uname -m) --instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt From 47cb969eeb99d9435fb9e3eb063f5dd2490f220b Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 24 Mar 2024 19:56:06 -0300 Subject: [PATCH 292/378] Move env var definition --- .github/workflows/macosx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 9b5149c1..c477157c 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -21,8 +21,8 @@ jobs: CC: clang CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" - PKG_CONFIG_PATH: "$(brew --prefix)/opt/libxml2/lib/pkgconfig" run: | + export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" python -m build rm -rf build/ - name: Set environment variables From 497971cfe6d0f79cbc54f59f6c4b93f740c27c53 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Mon, 25 Mar 2024 07:17:16 -0300 Subject: [PATCH 293/378] Remove PyXmlSec_CheckLibXmlLibraryVersion check --- src/lxml.c | 17 ----------------- 1 file changed, 17 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index bb7e6a96..6286cacb 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -47,18 +47,6 @@ long PyXmlSec_GetLibXmlCompiledVersionPatch() { return XMLSEC_EXTRACT_PATCH(LIBXML_VERSION); } -static int PyXmlSec_CheckLibXmlLibraryVersion(void) { - // Make sure that the version of libxml2 that we were compiled against is the same as the one - // that is loaded. If there is a version mismatch, we could run into segfaults. - - if (PyXmlSec_GetLibXmlVersionMajor() != PyXmlSec_GetLibXmlCompiledVersionMajor() || - PyXmlSec_GetLibXmlVersionMinor() != PyXmlSec_GetLibXmlCompiledVersionMinor()) { - return -1; - } - - return 0; -} - static int PyXmlSec_CheckLxmlLibraryVersion(void) { // Make sure that the version of libxml2 lxml is using is the same as the one we are using. Because // we pass trees between the two libraries, we need to make sure that they are using the same version @@ -104,11 +92,6 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { } int PyXmlSec_InitLxmlModule(void) { - if (PyXmlSec_CheckLibXmlLibraryVersion() < 0) { - PyXmlSec_SetLastError("xmlsec libxml2 library compiled version vs runtime version mismatch"); - return -1; - } - if (PyXmlSec_CheckLxmlLibraryVersion() < 0) { PyXmlSec_SetLastError("lxml & xmlsec libxml2 library version mismatch"); return -1; From c7e3208822245f5a3cc1dd04cdeb11125be3945f Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Mon, 25 Mar 2024 11:08:36 -0300 Subject: [PATCH 294/378] Add type hints --- src/xmlsec/__init__.pyi | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/xmlsec/__init__.pyi b/src/xmlsec/__init__.pyi index 6c326f56..9cfc8cc6 100644 --- a/src/xmlsec/__init__.pyi +++ b/src/xmlsec/__init__.pyi @@ -13,6 +13,8 @@ from xmlsec.constants import __Transform as Transform _E = TypeVar('_E', bound=_Element) def enable_debug_trace(enabled: bool = ...) -> None: ... +def get_libxml_version() -> tuple[int, int, int]: ... +def get_libxml_compiled_version() -> tuple[int, int, int]: ... def init() -> None: ... def shutdown() -> None: ... def cleanup_callbacks() -> None: ... From e7cbb7c8c40698a7b75c57cd59c47d356c2485e7 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 27 Mar 2024 09:36:17 -0300 Subject: [PATCH 295/378] Update checks based on some code review feedback. --- src/lxml.c | 21 +++++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index 6286cacb..7be62dad 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -67,18 +67,31 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { if (version == NULL) { goto FINALIZE; } - if (!PyTuple_Check(version) || PyTuple_Size(version) != 3) { + if (!PyTuple_Check(version) || PyTuple_Size(version) < 2) { goto FINALIZE; } PyObject* major = PyTuple_GetItem(version, 0); PyObject* minor = PyTuple_GetItem(version, 1); + if (PyErr_Occurred()) { + goto FINALIZE; + } + if (!PyLong_Check(major) || !PyLong_Check(minor)) { goto FINALIZE; } - if (PyLong_AsLong(major) != PyXmlSec_GetLibXmlVersionMajor() || PyLong_AsLong(minor) != PyXmlSec_GetLibXmlVersionMinor()) { + long lxml_major = PyLong_AsLong(major); + long lxml_minor = PyLong_AsLong(minor); + long xmlsec_major = PyXmlSec_GetLibXmlVersionMajor(); + long xmlsec_minor = PyXmlSec_GetLibXmlVersionMinor(); + + if (PyErr_Occurred()) { + goto FINALIZE; + } + + if (lxml_major != xmlsec_major || lxml_minor != xmlsec_minor) { goto FINALIZE; } @@ -88,6 +101,10 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { // Cleanup our references, and return the result Py_XDECREF(lxml); Py_XDECREF(version); + + // Clear any errors that may have occurred + PyErr_Clear(); + return result; } From 802904edd0edb09cbfab854a527622c4d3019ff1 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 28 Mar 2024 09:36:20 -0300 Subject: [PATCH 296/378] Make sure exception is handled when getting tuple item Co-authored-by: scoder --- src/lxml.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index 7be62dad..f5b74b6a 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -72,9 +72,11 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { } PyObject* major = PyTuple_GetItem(version, 0); + if (major == NULL) { + goto FINALIZE; + } PyObject* minor = PyTuple_GetItem(version, 1); - - if (PyErr_Occurred()) { + if (minor == NULL) { goto FINALIZE; } From 8ca3bdca7b825a92bbdcbffec643429266891b34 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 28 Mar 2024 09:37:24 -0300 Subject: [PATCH 297/378] Revert changes to version comparison Co-authored-by: scoder --- src/lxml.c | 11 +---------- 1 file changed, 1 insertion(+), 10 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index f5b74b6a..02211a3a 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -84,16 +84,7 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { goto FINALIZE; } - long lxml_major = PyLong_AsLong(major); - long lxml_minor = PyLong_AsLong(minor); - long xmlsec_major = PyXmlSec_GetLibXmlVersionMajor(); - long xmlsec_minor = PyXmlSec_GetLibXmlVersionMinor(); - - if (PyErr_Occurred()) { - goto FINALIZE; - } - - if (lxml_major != xmlsec_major || lxml_minor != xmlsec_minor) { + if (PyLong_AsLong(major) != PyXmlSec_GetLibXmlVersionMajor() || PyLong_AsLong(minor) != PyXmlSec_GetLibXmlVersionMinor()) { goto FINALIZE; } From b184cfe8f6b1a9592ff3e58aa2a93067d49bd5d4 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 28 Mar 2024 09:37:59 -0300 Subject: [PATCH 298/378] Clear any potential exceptions before Py_XDECREF Co-authored-by: scoder --- src/lxml.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/lxml.c b/src/lxml.c index 02211a3a..c98e933b 100644 --- a/src/lxml.c +++ b/src/lxml.c @@ -91,13 +91,13 @@ static int PyXmlSec_CheckLxmlLibraryVersion(void) { result = 0; FINALIZE: + // Clear any errors that may have occurred + PyErr_Clear(); + // Cleanup our references, and return the result Py_XDECREF(lxml); Py_XDECREF(version); - // Clear any errors that may have occurred - PyErr_Clear(); - return result; } From 06f6e46ff1600bae93965bad3ca8f75c52ab41d5 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 5 Apr 2024 15:11:05 +0200 Subject: [PATCH 299/378] Add more manylinux distros to workflow (#301) --- .github/workflows/manylinux.yml | 9 ++++++++- setup.py | 3 +-- 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 6d2dbb1a..f620ba44 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -1,13 +1,20 @@ name: manylinux on: [push, pull_request] jobs: - pep513: + manylinux: runs-on: ubuntu-latest + env: + # python-xmlsec is not compatible with xmlsec1 v1.3.3. + # So we need to use the rc until the next release. + # TODO: Remove it when xmlsec1 v1.3.4 is fully released. + PYXMLSEC_XMLSEC1_VERSION: "1.3.4-rc1" strategy: matrix: python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] image: - manylinux2014_x86_64 + - manylinux_2_28_x86_64 + - musllinux_1_1_x86_64 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 diff --git a/setup.py b/setup.py index 277a8892..2d8347f7 100644 --- a/setup.py +++ b/setup.py @@ -238,7 +238,7 @@ def prepare_static_build_win(self): ext.include_dirs = [str(p.absolute()) for p in includes] def prepare_static_build_linux(self): - self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1q') + self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1t') self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION') self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION') self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION') @@ -391,7 +391,6 @@ def prepare_static_build_linux(self): prefix_arg, '--disable-dependency-tracking', '--disable-shared', - '--enable-rebuild-docs=no', '--without-lzma', '--without-python', '--with-iconv={}'.format(self.prefix_dir), From d48d165f1555b81615f3e43e51ff2e5cd8e7d831 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 5 Apr 2024 16:25:38 +0200 Subject: [PATCH 300/378] Fix pre-commit check (#302) --- tests/softhsm_setup.py | 108 +++++++++++++++++++---------------------- 1 file changed, 49 insertions(+), 59 deletions(-) diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index 432d4b1b..c2a805db 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -1,7 +1,7 @@ -""" -Testing the PKCS#11 shim layer. +"""Testing the PKCS#11 shim layer. + Heavily inspired by from https://github.com/IdentityPython/pyXMLSecurity by leifj -under licence "As is", see https://github.com/IdentityPython/pyXMLSecurity/blob/master/LICENSE.txt +under license "As is", see https://github.com/IdentityPython/pyXMLSecurity/blob/master/LICENSE.txt """ import logging @@ -13,7 +13,7 @@ import unittest from typing import Dict, List, Optional, Tuple -DATA_DIR = os.path.join(os.path.dirname(__file__), "data") +DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') def paths_for_component(component: str, default_paths: List[str]): @@ -25,7 +25,7 @@ def find_alts(component_name, alts: List[str]) -> str: for a in alts: if os.path.exists(a): return a - raise unittest.SkipTest("Required component is missing: {}".format(component_name)) + raise unittest.SkipTest('Required component is missing: {}'.format(component_name)) def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: @@ -45,7 +45,7 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: conf = f.read() msg = '[cmd: {cmd}] [code: {code}] [stdout: {out}] [stderr: {err}] [config: {conf}]' msg = msg.format( - cmd=" ".join(args), + cmd=' '.join(args), code=rv, out=out.strip(), err=err.strip(), @@ -113,36 +113,34 @@ def _temp_dir() -> str: return d -@unittest.skipIf(component_path['P11_MODULE'] is None, "SoftHSM PKCS11 module not installed") +@unittest.skipIf(component_path['P11_MODULE'] is None, 'SoftHSM PKCS11 module not installed') def setup() -> None: - logging.debug("Creating test pkcs11 token using softhsm") + logging.debug('Creating test pkcs11 token using softhsm') try: global softhsm_conf softhsm_conf = _temp_file() - logging.debug("Generating softhsm.conf") - with open(softhsm_conf, "w") as f: + logging.debug('Generating softhsm.conf') + with open(softhsm_conf, 'w') as f: if softhsm_version == 2: softhsm_db = _temp_dir() f.write( - """ + f""" # Generated by test -directories.tokendir = %s +directories.tokendir = {softhsm_db} objectstore.backend = file log.level = DEBUG """ - % softhsm_db ) else: softhsm_db = _temp_file() f.write( - """ + f""" # Generated by test -0:%s +0:{softhsm_db} """ - % softhsm_db ) - logging.debug("Initializing the token") + logging.debug('Initializing the token') out, err = run_cmd( [ component_path['SOFTHSM'], @@ -159,18 +157,8 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) - # logging.debug("Generating 1024 bit RSA key in token") - # run_cmd([component_path['PKCS11_TOOL'], - # '--module', component_path['P11_MODULE'], - # '-l', - # '-k', - # '--key-type', 'rsa:1024', - # '--id', 'a1b2', - # '--label', 'test', - # '--pin', 'secret1'], softhsm_conf=softhsm_conf) - hash_priv_key = _temp_file() - logging.debug("Converting test private key to format for softhsm") + logging.debug('Converting test private key to format for softhsm') run_cmd( [ component_path['OPENSSL'], @@ -189,7 +177,7 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) - logging.debug("Importing the test key to softhsm") + logging.debug('Importing the test key to softhsm') run_cmd( [ component_path['SOFTHSM'], @@ -207,40 +195,42 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) run_cmd( - [component_path['PKCS11_TOOL'], '--module', component_path['P11_MODULE'], '-l', '--pin', 'secret1', '-O'], + [ + component_path['PKCS11_TOOL'], + '--module', + component_path['P11_MODULE'], + '-l', + '--pin', + 'secret1', + '-O', + ], softhsm_conf=softhsm_conf, ) signer_cert_pem = _temp_file() openssl_conf = _temp_file() - logging.debug("Generating OpenSSL config for version {}".format(openssl_version)) - with open(openssl_conf, "w") as f: - # Might be needed with some versions of openssl, but in more recent versions dynamic_path breaks it. - # dynamic_path = ( - # "dynamic_path = %s" % component_path['P11_ENGINE'] - # if openssl_version.startswith(b'1.') - # else "" - # ) + logging.debug('Generating OpenSSL config for version %s', openssl_version) + with open(openssl_conf, 'w') as f: f.write( - "\n".join( + '\n'.join( [ - "openssl_conf = openssl_def", - "[openssl_def]", - "engines = engine_section", - "[engine_section]", - "pkcs11 = pkcs11_section", - "[req]", - "distinguished_name = req_distinguished_name", - "[req_distinguished_name]", - "[pkcs11_section]", - "engine_id = pkcs11", + 'openssl_conf = openssl_def', + '[openssl_def]', + 'engines = engine_section', + '[engine_section]', + 'pkcs11 = pkcs11_section', + '[req]', + 'distinguished_name = req_distinguished_name', + '[req_distinguished_name]', + '[pkcs11_section]', + 'engine_id = pkcs11', # dynamic_path, - "MODULE_PATH = %s" % component_path['P11_MODULE'], - "init = 0", + f"MODULE_PATH = {component_path['P11_MODULE']}", + 'init = 0', ] ) ) - with open(openssl_conf, "r") as f: + with open(openssl_conf, 'r') as f: logging.debug('-------- START DEBUG openssl_conf --------') logging.debug(f.readlines()) logging.debug('-------- END DEBUG openssl_conf --------') @@ -251,7 +241,7 @@ def setup() -> None: signer_cert_der = _temp_file() - logging.debug("Generating self-signed certificate") + logging.debug('Generating self-signed certificate') run_cmd( [ component_path['OPENSSL'], @@ -259,7 +249,7 @@ def setup() -> None: '-new', '-x509', '-subj', - "/CN=Test Signer", + '/CN=Test Signer', '-engine', 'pkcs11', '-config', @@ -292,7 +282,7 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) - logging.debug("Importing certificate into token") + logging.debug('Importing certificate into token') run_cmd( [ @@ -316,15 +306,15 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) - # TODO: Should be teardowned in teardown: + # TODO: Should be teardowned in teardown # noqa: T101 os.environ['SOFTHSM_CONF'] = softhsm_conf os.environ['SOFTHSM2_CONF'] = softhsm_conf except Exception as ex: - print("-" * 64) + print('-' * 64) traceback.print_exc() - print("-" * 64) - logging.error("PKCS11 tests disabled: unable to initialize test token: %s" % ex) + print('-' * 64) + logging.exception('PKCS11 tests disabled: unable to initialize test token') raise ex From 64d9bc1e2b23cffbf1dbcde23162b1ec3734e6a0 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 5 Apr 2024 17:14:15 +0200 Subject: [PATCH 301/378] Remove unsupported Python 3.5 type hints (#303) Tuple, Dict, List and Optional not supported in Python 3.5, so we can't use them. Using them breaks MacOS workflows. --- tests/softhsm_setup.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index c2a805db..ef34b6c0 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -11,24 +11,23 @@ import tempfile import traceback import unittest -from typing import Dict, List, Optional, Tuple DATA_DIR = os.path.join(os.path.dirname(__file__), 'data') -def paths_for_component(component: str, default_paths: List[str]): +def paths_for_component(component: str, default_paths): env_path = os.environ.get(component) return [env_path] if env_path else default_paths -def find_alts(component_name, alts: List[str]) -> str: +def find_alts(component_name, alts) -> str: for a in alts: if os.path.exists(a): return a raise unittest.SkipTest('Required component is missing: {}'.format(component_name)) -def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: +def run_cmd(args, softhsm_conf=None): env = {} if softhsm_conf is not None: env['SOFTHSM_CONF'] = softhsm_conf @@ -55,7 +54,7 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: return out, err -component_default_paths: Dict[str, List[str]] = { +component_default_paths = { 'P11_MODULE': [ '/usr/lib/softhsm/libsofthsm2.so', '/usr/lib/x86_64-linux-gnu/softhsm/libsofthsm2.so', @@ -85,7 +84,7 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: ], } -component_path: Dict[str, str] = { +component_path = { component_name: find_alts(component_name, paths_for_component(component_name, default_paths)) for component_name, default_paths in component_default_paths.items() } @@ -96,9 +95,9 @@ def run_cmd(args, softhsm_conf=None) -> Tuple[bytes, bytes]: openssl_version = subprocess.check_output([component_path['OPENSSL'], 'version'])[8:11].decode() -p11_test_files: List[str] = [] -softhsm_conf: Optional[str] = None -softhsm_db: Optional[str] = None +p11_test_files = [] +softhsm_conf = None +softhsm_db = None def _temp_file() -> str: From 2a0438684f90979a7dc7c36fe4a7b31e30e688b7 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 5 Apr 2024 17:45:41 +0200 Subject: [PATCH 302/378] Use old formatting to keep it compatible with Python 3.5 (#304) --- tests/softhsm_setup.py | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index ef34b6c0..247f1b18 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -123,20 +123,24 @@ def setup() -> None: if softhsm_version == 2: softhsm_db = _temp_dir() f.write( - f""" + """ # Generated by test -directories.tokendir = {softhsm_db} +directories.tokendir = {} objectstore.backend = file log.level = DEBUG -""" +""".format( + softhsm_db + ) ) else: softhsm_db = _temp_file() f.write( - f""" + """ # Generated by test -0:{softhsm_db} -""" +0:{} +""".format( + softhsm_db + ) ) logging.debug('Initializing the token') @@ -223,7 +227,7 @@ def setup() -> None: '[pkcs11_section]', 'engine_id = pkcs11', # dynamic_path, - f"MODULE_PATH = {component_path['P11_MODULE']}", + "MODULE_PATH = {}".format(component_path['P11_MODULE']), 'init = 0', ] ) From df37761539d0dd35ab428fbb4776e19591b2cc78 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:04:23 +0000 Subject: [PATCH 303/378] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 22.8.0 → 24.3.0](https://github.com/psf/black/compare/22.8.0...24.3.0) - [github.com/pre-commit/pre-commit-hooks: v4.3.0 → v4.5.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.3.0...v4.5.0) - [github.com/PyCQA/flake8: 5.0.4 → 7.0.0](https://github.com/PyCQA/flake8/compare/5.0.4...7.0.0) - [github.com/PyCQA/isort: 5.12.0 → 5.13.2](https://github.com/PyCQA/isort/compare/5.12.0...5.13.2) - [github.com/pre-commit/mirrors-mypy: v0.981 → v1.9.0](https://github.com/pre-commit/mirrors-mypy/compare/v0.981...v1.9.0) - [github.com/pre-commit/pygrep-hooks: v1.9.0 → v1.10.0](https://github.com/pre-commit/pygrep-hooks/compare/v1.9.0...v1.10.0) --- .pre-commit-config.yaml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bf877f39..9678ec68 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,14 +2,14 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black - rev: 22.8.0 + rev: 24.3.0 hooks: - id: black types: [] files: ^.*.pyi?$ exclude: ^doc/ - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.3.0 + rev: v4.5.0 hooks: - id: no-commit-to-branch - id: trailing-whitespace @@ -25,17 +25,17 @@ repos: - id: pretty-format-json args: [--autofix] - repo: https://github.com/PyCQA/flake8 - rev: 5.0.4 + rev: 7.0.0 hooks: - id: flake8 exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.12.0 + rev: 5.13.2 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy - rev: v0.981 + rev: v1.9.0 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) @@ -43,6 +43,6 @@ repos: files: ^.*.pyi?$ additional_dependencies: [lxml-stubs,types-docutils] - repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.9.0 + rev: v1.10.0 hooks: - id: rst-backticks From d5367145229dd316cc46f0df9e944dd28627bd56 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 18 Mar 2024 20:04:38 +0000 Subject: [PATCH 304/378] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 2d8347f7..f0da1a2d 100644 --- a/setup.py +++ b/setup.py @@ -133,7 +133,7 @@ def run(self): [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] ) # escape the XMLSEC_CRYPTO macro value, see mehcode/python-xmlsec#141 - for (key, value) in ext.define_macros: + for key, value in ext.define_macros: if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')): ext.define_macros.remove((key, value)) ext.define_macros.append((key, '"{0}"'.format(value))) From 18f325019d4ac2ecfe32dba6b6815a58f6fd7988 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 5 Apr 2024 23:51:22 +0200 Subject: [PATCH 305/378] Fix opensuse-tumbleweed workflow (#305) --- .github/workflows/opensuse-tumbleweed.yml | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/.github/workflows/opensuse-tumbleweed.yml b/.github/workflows/opensuse-tumbleweed.yml index 273f7f7f..2f4caf49 100644 --- a/.github/workflows/opensuse-tumbleweed.yml +++ b/.github/workflows/opensuse-tumbleweed.yml @@ -11,9 +11,13 @@ jobs: - uses: actions/checkout@v1 - name: Install build dependencies run: | - zypper -n install -t pattern devel_basis + zypper refresh + zypper update + # The follwoing installs "devel_basis" pattern since installing the pattern fails because of few + # incompatibilty issues among packages + zypper -n install autoconf automake binutils bison cpp cpp13 flex gawk gcc gcc13 gdbm-devel gettext-runtime gettext-tools glibc-devel info kbd kbd-legacy libapparmor1 libasan8 libatomic1 libctf-nobfd0 libctf0 libdb-4_8 libfl-devel libfl2 libgdbm6 libgdbm_compat4 libgomp1 libhwasan0 libisl23 libitm1 libkmod2 liblsan0 libltdl7 libmpc3 libmpfr6 libseccomp2 libtextstyle0 libtool libtsan2 libubsan1 libxcrypt-devel libzio1 linux-glibc-devel m4 make makeinfo ncurses-devel pam-config patch perl perl-Text-Unidecode perl-base purge-kernels-service system-user-nobody systemd systemd-default-settings systemd-default-settings-branding-openSUSE systemd-presets-branding-openSUSE systemd-presets-common-SUSE tack update-alternatives zlib-devel PKGVER_NO_DOT=$(tr -d '.' <<< ${{ matrix.python-version }}) - zypper -n install git libxmlsec1-openssl1 xmlsec1-openssl-devel python${PKGVER_NO_DOT}-devel python${PKGVER_NO_DOT}-pip + zypper -n install git libxmlsec1-openssl1 xmlsec1-openssl-devel python${PKGVER_NO_DOT}-devel python${{ matrix.python-version }} -m venv .venv .venv/bin/python -m pip install --upgrade pip setuptools wheel - name: Build linux_x86_64 wheel @@ -22,7 +26,7 @@ jobs: rm -rf build/ - name: Install test dependencies run: | - .venv/bin/python -m pip install --upgrade -r requirements-test.txt + .venv/bin/python -m pip install --upgrade --no-binary=lxml -r requirements-test.txt .venv/bin/python -m pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ - name: Run tests run: | From 83ee6324c6e1aaeafef96a43a6584e3991fa2272 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 20:18:14 -0300 Subject: [PATCH 306/378] Fetch latest openssl version, when doing static build. --- .github/workflows/manylinux.yml | 6 ++- setup.py | 83 +++++++++++++++++++++++---------- 2 files changed, 64 insertions(+), 25 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index f620ba44..ea05780b 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -18,11 +18,15 @@ jobs: container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 - - name: Install build dependencies + - name: Install python build dependencies run: | # https://github.com/actions/runner/issues/2033 chown -R $(id -u):$(id -g) $PWD /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build + - name: Install system build dependencies (manylinux) + run: | + yum install -y perl-core + if: contains(matrix.image, 'manylinux') - name: Set environment variables shell: bash run: | diff --git a/setup.py b/setup.py index f0da1a2d..32c4d134 100644 --- a/setup.py +++ b/setup.py @@ -13,7 +13,8 @@ from distutils.errors import DistutilsError from distutils.version import StrictVersion as Version from pathlib import Path -from urllib.request import urlcleanup, urljoin, urlopen, urlretrieve +from urllib.parse import urljoin +from urllib.request import urlcleanup, urlopen, urlretrieve, Request from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig @@ -31,31 +32,60 @@ def handle_starttag(self, tag, attrs): self.hrefs.append(value) +def make_request(url, github_token=None, json_response=False): + headers = {'User-Agent': 'https://github.com/xmlsec/python-xmlsec'} + if github_token: + headers['authorization'] = "Bearer " + github_token + request = Request(url, headers=headers) + with contextlib.closing(urlopen(request)) as r: + if json_response: + return json.load(r) + else: + charset = r.headers.get_content_charset() or 'utf-8' + content = r.read().decode(charset) + return content + + def latest_release_from_html(url, matcher): - with contextlib.closing(urlopen(url)) as r: - charset = r.headers.get_content_charset() or 'utf-8' - content = r.read().decode(charset) - collector = HrefCollector() - collector.feed(content) - hrefs = collector.hrefs - - def comp(text): - try: - return Version(matcher.match(text).groupdict()['version']) - except (AttributeError, ValueError): - return Version('0.0') + content = make_request(url) + collector = HrefCollector() + collector.feed(content) + hrefs = collector.hrefs + + def comp(text): + try: + return Version(matcher.match(text).groupdict()['version']) + except (AttributeError, ValueError): + return Version('0.0') - latest = max(hrefs, key=comp) - return '{}/{}'.format(url, latest) + latest = max(hrefs, key=comp) + return '{}/{}'.format(url, latest) def latest_release_from_gnome_org_cache(url, lib_name): cache_url = '{}/cache.json'.format(url) - with contextlib.closing(urlopen(cache_url)) as r: - cache = json.load(r) - latest_version = cache[2][lib_name][-1] - latest_source = cache[1][lib_name][latest_version]['tar.xz'] - return '{}/{}'.format(url, latest_source) + cache = make_request(cache_url, json_response=True) + latest_version = cache[2][lib_name][-1] + latest_source = cache[1][lib_name][latest_version]['tar.xz'] + return '{}/{}'.format(url, latest_source) + + +def latest_release_from_github_api(repo): + api_url = 'https://api.github.com/repos/{}/releases'.format(repo) + + # if we are running in CI, pass along the GH_TOKEN, so we don't get rate limited + token = os.environ.get("GH_TOKEN") + if token: + log.info("Using GitHub token to avoid rate limiting") + api_releases = make_request(api_url, token, json_response=True) + releases = [r['tarball_url'] for r in api_releases if r['prerelease'] is False and r['draft'] is False] + if not releases: + raise DistutilsError('No release found for {}'.format(repo)) + return releases[0] + + +def latest_openssl_release(): + return latest_release_from_github_api('openssl/openssl') def latest_zlib_release(): @@ -238,7 +268,7 @@ def prepare_static_build_win(self): ext.include_dirs = [str(p.absolute()) for p in includes] def prepare_static_build_linux(self): - self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '1.1.1t') + self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION') self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION') self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION') self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION') @@ -250,8 +280,13 @@ def prepare_static_build_linux(self): if openssl_tar is None: self.info('{:10}: {}'.format('OpenSSL', 'source tar not found, downloading ...')) openssl_tar = self.libs_dir / 'openssl.tar.gz' - self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) - urlretrieve('https://www.openssl.org/source/openssl-{}.tar.gz'.format(self.openssl_version), str(openssl_tar)) + if self.openssl_version is None: + url = latest_openssl_release() + self.info('{:10}: {}'.format('OpenSSL', 'PYXMLSEC_OPENSSL_VERSION unset, downloading latest from {}'.format(url))) + else: + url = 'https://api.github.com/repos/openssl/openssl/tarball/openssl-{}'.format(self.openssl_version) + self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) + urlretrieve(url, str(openssl_tar)) # fetch zlib zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) @@ -361,7 +396,7 @@ def prepare_static_build_linux(self): self.info('Building OpenSSL') openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - subprocess.check_output(['./config', prefix_arg, 'no-shared', '-fPIC'], cwd=str(openssl_dir), env=env) + subprocess.check_output(['./config', prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'], cwd=str(openssl_dir), env=env) subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) subprocess.check_output( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env From 73cca3cabf203b6660ce3396621047789bf77d94 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 20 Mar 2024 23:23:29 +0000 Subject: [PATCH 307/378] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/setup.py b/setup.py index 32c4d134..cdf95c41 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from distutils.version import StrictVersion as Version from pathlib import Path from urllib.parse import urljoin -from urllib.request import urlcleanup, urlopen, urlretrieve, Request +from urllib.request import Request, urlcleanup, urlopen, urlretrieve from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig From a51d1ff1ef0b1bb98df97c91bfc0f4504392ff9c Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 21:02:39 -0300 Subject: [PATCH 308/378] Allow static build from MacOS --- setup.py | 81 ++++++++++++++++++++++++++++++++++++++++++++++---------- 1 file changed, 67 insertions(+), 14 deletions(-) diff --git a/setup.py b/setup.py index cdf95c41..7b5d43d6 100644 --- a/setup.py +++ b/setup.py @@ -108,6 +108,17 @@ def latest_xmlsec_release(): return latest_release_from_html('https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz')) +class CrossCompileInfo: + def __init__(self, host, arch, compiler): + self.host = host + self.arch = arch + self.compiler = compiler + + @property + def triplet(self): + return "{}-{}-{}".format(self.host, self.arch, self.compiler) + + class build_ext(build_ext_orig): def info(self, message): self.announce(message, level=log.INFO) @@ -136,7 +147,9 @@ def run(self): if sys.platform == 'win32': self.prepare_static_build_win() elif 'linux' in sys.platform: - self.prepare_static_build_linux() + self.prepare_static_build(sys.platform) + elif 'darwin' in sys.platform: + self.prepare_static_build(sys.platform) else: import pkgconfig @@ -267,7 +280,7 @@ def prepare_static_build_win(self): includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) ext.include_dirs = [str(p.absolute()) for p in includes] - def prepare_static_build_linux(self): + def prepare_static_build(self, build_platform): self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION') self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION') self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION') @@ -387,16 +400,42 @@ def prepare_static_build_linux(self): prefix_arg = '--prefix={}'.format(self.prefix_dir) - cflags = ['-fPIC'] env = os.environ.copy() - if 'CFLAGS' in env: - env['CFLAGS'].append(' '.join(cflags)) - else: - env['CFLAGS'] = ' '.join(cflags) + cflags = [] + if env.get('CFLAGS'): + cflags.append(env['CFLAGS']) + cflags.append('-fPIC') + ldflags = [] + if env.get('LDFLAGS'): + ldflags.append(env['LDFLAGS']) + + cross_compiling = False + if build_platform == 'darwin': + import platform + + arch = self.plat_name.rsplit('-', 1)[1] + if arch != platform.machine() and arch in ('x86_64', 'arm64'): + self.info('Cross-compiling for {}'.format(arch)) + cflags.append('-arch {}'.format(arch)) + ldflags.append('-arch {}'.format(arch)) + cross_compiling = CrossCompileInfo('darwin64', arch, 'cc') + major_version, minor_version = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) + if major_version >= 11: + if 'MACOSX_DEPLOYMENT_TARGET' not in env: + env['MACOSX_DEPLOYMENT_TARGET'] = "11.0" + + env['CFLAGS'] = ' '.join(cflags) + env['LDFLAGS'] = ' '.join(ldflags) self.info('Building OpenSSL') openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - subprocess.check_output(['./config', prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'], cwd=str(openssl_dir), env=env) + openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] + if cross_compiling: + openssl_config_cmd.insert(0, './Configure') + openssl_config_cmd.append(cross_compiling.triplet) + else: + openssl_config_cmd.insert(0, './config') + subprocess.check_output(openssl_config_cmd, cwd=str(openssl_dir), env=env) subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) subprocess.check_output( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env @@ -408,10 +447,22 @@ def prepare_static_build_linux(self): subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) + host_arg = "" + if cross_compiling: + host_arg = '--host={}'.format(cross_compiling.arch) + self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) subprocess.check_output( - ['./configure', prefix_arg, '--disable-dependency-tracking', '--disable-shared'], cwd=str(libiconv_dir), env=env + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + host_arg, + ], + cwd=str(libiconv_dir), + env=env, ) subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) subprocess.check_output( @@ -430,6 +481,7 @@ def prepare_static_build_linux(self): '--without-python', '--with-iconv={}'.format(self.prefix_dir), '--with-zlib={}'.format(self.prefix_dir), + host_arg, ], cwd=str(libxml2_dir), env=env, @@ -450,6 +502,7 @@ def prepare_static_build_linux(self): '--without-python', '--without-crypto', '--with-libxml-prefix={}'.format(self.prefix_dir), + host_arg, ], cwd=str(libxslt_dir), env=env, @@ -460,10 +513,8 @@ def prepare_static_build_linux(self): ) self.info('Building xmlsec1') - if 'LDFLAGS' in env: - env['LDFLAGS'].append(' -lpthread') - else: - env['LDFLAGS'] = '-lpthread' + ldflags.append('-lpthread') + env['LDFLAGS'] = ' '.join(ldflags) xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) subprocess.check_output( [ @@ -480,6 +531,7 @@ def prepare_static_build_linux(self): '--with-openssl={}'.format(self.prefix_dir), '--with-libxml={}'.format(self.prefix_dir), '--with-libxslt={}'.format(self.prefix_dir), + host_arg, ], cwd=str(xmlsec1_dir), env=env, @@ -517,7 +569,8 @@ def prepare_static_build_linux(self): ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) ext.library_dirs = [] - ext.libraries = ['m', 'rt'] + if build_platform == 'linux': + ext.libraries = ['m', 'rt'] extra_objects = [ 'libxmlsec1.a', 'libxslt.a', From 47e711b0317955f0f363985606f0f9fdf6939bea Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 7 Apr 2024 19:13:33 -0300 Subject: [PATCH 309/378] Add CI action for OSX static build --- .github/workflows/macosx.yml | 3 +++ setup.py | 6 +++--- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index c477157c..5baa1e44 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -6,6 +6,7 @@ jobs: strategy: matrix: python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] + static_deps: ["static", ""] steps: - uses: actions/checkout@v3 - name: Setup Python @@ -21,6 +22,7 @@ jobs: CC: clang CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" + PYXMLSEC_STATIC_DEPS: ${{ matrix.static_deps }} run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" python -m build @@ -43,3 +45,4 @@ jobs: /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=$(uname -m) --instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt + if: matrix.static_deps != 'static' diff --git a/setup.py b/setup.py index 7b5d43d6..7e9e8ba1 100644 --- a/setup.py +++ b/setup.py @@ -38,11 +38,11 @@ def make_request(url, github_token=None, json_response=False): headers['authorization'] = "Bearer " + github_token request = Request(url, headers=headers) with contextlib.closing(urlopen(request)) as r: + charset = r.headers.get_content_charset() or 'utf-8' + content = r.read().decode(charset) if json_response: - return json.load(r) + return json.loads(content) else: - charset = r.headers.get_content_charset() or 'utf-8' - content = r.read().decode(charset) return content From 6922ccba43f544b90aaa782dfd7f8ff4f51a1103 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 8 Apr 2024 20:18:07 +0000 Subject: [PATCH 310/378] [pre-commit.ci] pre-commit autoupdate MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/pre-commit/pre-commit-hooks: v4.5.0 → v4.6.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.5.0...v4.6.0) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 9678ec68..820778ef 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -9,7 +9,7 @@ repos: files: ^.*.pyi?$ exclude: ^doc/ - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.5.0 + rev: v4.6.0 hooks: - id: no-commit-to-branch - id: trailing-whitespace From e9251d34b735caac7160735872d5deeb7910285d Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Sun, 7 Apr 2024 21:56:55 -0300 Subject: [PATCH 311/378] Fix linux brew workflow --- .github/workflows/linuxbrew.yml | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 191e2001..886bd8c9 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -3,26 +3,28 @@ on: [push, pull_request] jobs: linuxbrew: runs-on: ubuntu-latest + strategy: + matrix: + python: ["3.8", "3.9", "3.10", "3.11"] steps: - uses: actions/checkout@v3 - - name: Setup Python - uses: actions/setup-python@v4 - with: - python-version: ${{ matrix.python }} - - name: Install build dependencies + - name: Install brew run: | sudo apt install -y build-essential procps curl file git /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" - test -d ~/.linuxbrew && eval $(~/.linuxbrew/bin/brew shellenv) - test -r ~/.bash_profile && echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.bash_profile - echo "eval \$($(brew --prefix)/bin/brew shellenv)" >>~/.profile + echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH + - name: Install build dependencies + run: | brew update - brew install python gcc libxml2 libxmlsec1 pkg-config + brew install python@${{ matrix.python }} gcc libxml2 libxmlsec1 pkg-config + echo "/home/linuxbrew/.linuxbrew/opt/python@${{ matrix.python }}/libexec/bin" >> $GITHUB_PATH + - name: Install python dependencies + run: | pip3 install --upgrade setuptools wheel build - ln -s $(brew --prefix)/bin/gcc-12 $(brew --prefix)/bin/gcc-5 - ls -l $(brew --prefix)/bin/gcc* - name: Build linux_x86_64 wheel run: | + export CFLAGS="-I$(brew --prefix)/include" + export LDFLAGS="-L$(brew --prefix)/lib" python3 -m build rm -rf build/ - name: Install test dependencies From e789da55100ab1ce96d2f9d0d798d5a67b16b74d Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Mon, 8 Apr 2024 21:59:40 -0300 Subject: [PATCH 312/378] Add gh_token to avoid getting rate limited --- .github/workflows/macosx.yml | 1 + .github/workflows/manylinux.yml | 1 + 2 files changed, 2 insertions(+) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 5baa1e44..6d0548e8 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -23,6 +23,7 @@ jobs: CFLAGS: "-fprofile-instr-generate -fcoverage-mapping" LDFLAGS: "-fprofile-instr-generate -fcoverage-mapping" PYXMLSEC_STATIC_DEPS: ${{ matrix.static_deps }} + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" python -m build diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index ea05780b..a80ad67b 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -34,6 +34,7 @@ jobs: - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | /opt/python/${{ matrix.python-abi }}/bin/python -m build - name: Label manylinux wheel From b864c31c2c887e7ddf4fdc6c9faa2bfd20ef6d64 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 20 Mar 2024 21:12:14 -0300 Subject: [PATCH 313/378] Use ci build wheel to build staticly linked wheels for linux and OSX --- .github/workflows/wheels.yml | 122 +++++++++++++++++++++++++++++++++++ pyproject.toml | 28 ++++++++ 2 files changed, 150 insertions(+) create mode 100644 .github/workflows/wheels.yml diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml new file mode 100644 index 00000000..0d83f59b --- /dev/null +++ b/.github/workflows/wheels.yml @@ -0,0 +1,122 @@ +name: Wheel build + +on: + release: + types: [created] + schedule: + # ┌───────────── minute (0 - 59) + # │ ┌───────────── hour (0 - 23) + # │ │ ┌───────────── day of the month (1 - 31) + # │ │ │ ┌───────────── month (1 - 12 or JAN-DEC) + # │ │ │ │ ┌───────────── day of the week (0 - 6 or SUN-SAT) + # │ │ │ │ │ + - cron: "42 3 * * 4" + push: + pull_request: + workflow_dispatch: + +permissions: {} + +jobs: + sdist: + runs-on: ubuntu-latest + + permissions: + contents: write + + steps: + - uses: actions/checkout@v4.1.1 + with: + fetch-depth: 0 + + - name: Set up Python + uses: actions/setup-python@v5.0.0 + with: + python-version: "3.x" + + - name: Install build dependencies + run: | + pip install --upgrade pip setuptools wheel + + - name: Package source dist + run: python setup.py sdist + + - name: Install test dependencies + run: | + sudo apt-get update -y -q + sudo apt-get install -y -q libxml2-dev libxslt1-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl + pip install --upgrade -r requirements-test.txt --no-binary lxml + pip install dist/xmlsec-$(python setup.py --version).tar.gz + + - name: Run tests + run: pytest -v --color=yes + + - name: Upload sdist + uses: actions/upload-artifact@v4.3.1 + with: + name: sdist + path: dist/*.tar.gz + + generate-wheels-matrix: + # Create a matrix of all architectures & versions to build. + # This enables the next step to run cibuildwheel in parallel. + # From https://iscinumpy.dev/post/cibuildwheel-2-10-0/#only-210 + name: Generate wheels matrix + runs-on: ubuntu-latest + outputs: + include: ${{ steps.set-matrix.outputs.include }} + steps: + - uses: actions/checkout@v4 + - name: Install cibuildwheel + # Nb. keep cibuildwheel version pin consistent with job below + run: pipx install cibuildwheel==2.16.5 + - id: set-matrix + # Once we have the windows build figured out, it can be added here + # by updating the matrix to include windows builds as well. + # See example here: + # https://github.com/lxml/lxml/blob/3ccc7d583e325ceb0ebdf8fc295bbb7fc8cd404d/.github/workflows/wheels.yml#L95C1-L106C51 + run: | + MATRIX=$( + { + cibuildwheel --print-build-identifiers --platform linux \ + | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ + && cibuildwheel --print-build-identifiers --platform macos \ + | jq -nRc '{"only": inputs, "os": "macos-latest"}' + } | jq -sc + ) + echo "include=$MATRIX" + echo "include=$MATRIX" >> $GITHUB_OUTPUT + + build_wheels: + name: Build for ${{ matrix.only }} + needs: generate-wheels-matrix + runs-on: ${{ matrix.os }} + + strategy: + fail-fast: false + matrix: + include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} + + steps: + - name: Check out the repo + uses: actions/checkout@v4 + with: + fetch-depth: 0 + + - name: Set up QEMU + if: runner.os == 'Linux' + uses: docker/setup-qemu-action@v3 + with: + platforms: all + + - name: Build wheels + uses: pypa/cibuildwheel@v2.16.5 + with: + only: ${{ matrix.only }} + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - uses: actions/upload-artifact@v4.3.1 + with: + path: ./wheelhouse/*.whl + name: xmlsec-wheel-${{ matrix.only }} diff --git a/pyproject.toml b/pyproject.toml index e28878e3..f3ddbdbb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -45,3 +45,31 @@ known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] [build-system] requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] + +[tool.cibuildwheel] +build-verbosity = 1 +build-frontend = "build" +skip = ["pp*", "*-musllinux_i686"] +test-command = "pytest -v --color=yes {package}/tests" +before-test = "pip install -r requirements-test.txt" +test-skip = "*-macosx_arm64" + +[tool.cibuildwheel.environment] +PYXMLSEC_STATIC_DEPS = "true" + +[tool.cibuildwheel.linux] +archs = ["x86_64", "aarch64", "i686"] +environment-pass = [ + "PYXMLSEC_LIBXML2_VERSION", + "PYXMLSEC_LIBXSLT_VERSION", + "PYXMLSEC_STATIC_DEPS", + "GH_TOKEN" +] + +[tool.cibuildwheel.macos] +archs = ["x86_64", "arm64"] +before-all = "brew install perl" + +[[tool.cibuildwheel.overrides]] +select = "*-manylinux*" +before-all = "yum install -y perl-core" From 6741ff80cf0df8c8e9e611baaf77f4c2c68321a1 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Tue, 9 Apr 2024 16:35:03 -0300 Subject: [PATCH 314/378] Make skipped wheel builds match upstream lxml. --- pyproject.toml | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/pyproject.toml b/pyproject.toml index f3ddbdbb..99927b4b 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -49,7 +49,16 @@ requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>= [tool.cibuildwheel] build-verbosity = 1 build-frontend = "build" -skip = ["pp*", "*-musllinux_i686"] +skip = [ + "pp*", + "*-musllinux_i686", + # LXML doesn't publish wheels for these platforms, which makes it + # difficult for us to build wheels, so we exclude them. + "cp36-manylinux_aarch64", + "cp37-manylinux_aarch64", + "cp36-musllinux_aarch64", + "cp37-musllinux_aarch64", +] test-command = "pytest -v --color=yes {package}/tests" before-test = "pip install -r requirements-test.txt" test-skip = "*-macosx_arm64" From 3edf947c05c5e853dc77cc66c8dcc0b19735c033 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Tue, 9 Apr 2024 16:47:00 -0300 Subject: [PATCH 315/378] Remove PYXMLSEC_XMLSEC1_VERSION override. --- .github/workflows/manylinux.yml | 5 ----- 1 file changed, 5 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index a80ad67b..a44776b3 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -3,11 +3,6 @@ on: [push, pull_request] jobs: manylinux: runs-on: ubuntu-latest - env: - # python-xmlsec is not compatible with xmlsec1 v1.3.3. - # So we need to use the rc until the next release. - # TODO: Remove it when xmlsec1 v1.3.4 is fully released. - PYXMLSEC_XMLSEC1_VERSION: "1.3.4-rc1" strategy: matrix: python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] From 1b3b527fd27ea0f48ee3c69354249d90d56cec23 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Wed, 17 Apr 2024 18:16:58 +0200 Subject: [PATCH 316/378] Add windows wheel build (#313) --- .github/workflows/wheels.yml | 4 +++- pyproject.toml | 3 +++ setup.py | 19 ++++++++++--------- 3 files changed, 16 insertions(+), 10 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 0d83f59b..ccd62cf8 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -81,7 +81,9 @@ jobs: cibuildwheel --print-build-identifiers --platform linux \ | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ && cibuildwheel --print-build-identifiers --platform macos \ - | jq -nRc '{"only": inputs, "os": "macos-latest"}' + | jq -nRc '{"only": inputs, "os": "macos-latest"}' \ + && cibuildwheel --print-build-identifiers --platform windows \ + | jq -nRc '{"only": inputs, "os": "windows-2019"}' } | jq -sc ) echo "include=$MATRIX" diff --git a/pyproject.toml b/pyproject.toml index 99927b4b..9b6469d4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -79,6 +79,9 @@ environment-pass = [ archs = ["x86_64", "arm64"] before-all = "brew install perl" +[tool.cibuildwheel.windows] +archs = ["AMD64", "x86"] + [[tool.cibuildwheel.overrides]] select = "*-manylinux*" before-all = "yum install -y perl-core" diff --git a/setup.py b/setup.py index 7e9e8ba1..92588ebc 100644 --- a/setup.py +++ b/setup.py @@ -213,19 +213,19 @@ def run(self): super(build_ext, self).run() def prepare_static_build_win(self): - release_url = 'https://github.com/bgaifullin/libxml2-win-binaries/releases/download/v2018.08/' - if sys.maxsize > 2147483647: + release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2024.04.17/' + if sys.maxsize > 2147483647: # 2.0 GiB suffix = 'win64' else: suffix = 'win32' libs = [ - 'libxml2-2.9.4.{}.zip'.format(suffix), - 'libxslt-1.1.29.{}.zip'.format(suffix), - 'zlib-1.2.8.{}.zip'.format(suffix), - 'iconv-1.14.{}.zip'.format(suffix), - 'openssl-1.0.1.{}.zip'.format(suffix), - 'xmlsec-1.2.24.{}.zip'.format(suffix), + 'libxml2-2.11.7.{}.zip'.format(suffix), + 'libxslt-1.1.37.{}.zip'.format(suffix), + 'zlib-1.2.12.{}.zip'.format(suffix), + 'iconv-1.16-1.{}.zip'.format(suffix), + 'openssl-3.0.8.{}.zip'.format(suffix), + 'xmlsec-1.3.4.{}.zip'.format(suffix), ] for libfile in libs: @@ -262,7 +262,7 @@ def prepare_static_build_win(self): ext.libraries = [ 'libxmlsec_a', 'libxmlsec-openssl_a', - 'libeay32', + 'libcrypto', 'iconv_a', 'libxslt_a', 'libexslt_a', @@ -599,6 +599,7 @@ def prepare_static_build(self, build_platform): use_scm_version=True, description='Python bindings for the XML Security Library', long_description=long_desc, + long_description_content_type='text/markdown', ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, python_requires='>=3.5', From 67cd4ac73e4fceac4b4eb6a320067cad33f79213 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Miro=20Hron=C4=8Dok?= Date: Wed, 19 Jun 2024 17:43:07 +0200 Subject: [PATCH 317/378] Explicitly cast the pointer type in PyXmlSec_ClearReplacedNodes Fixes https://github.com/xmlsec/python-xmlsec/issues/323 --- src/enc.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/enc.c b/src/enc.c index 5453ef99..c2bc94bf 100644 --- a/src/enc.c +++ b/src/enc.c @@ -204,7 +204,7 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; // if n has references, it will not be deleted - elem = PyXmlSec_elementFactory(doc, n); + elem = (PyXmlSec_LxmlElementPtr*)PyXmlSec_elementFactory(doc, n); if (NULL == elem) xmlFreeNode(n); else From e2ca04f26a0679db01feb0687d6ae93542bcb47f Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 30 Oct 2024 22:03:02 -0300 Subject: [PATCH 318/378] Build wheel for python 3.13 --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ccd62cf8..c3aaf48d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -69,7 +69,7 @@ jobs: - uses: actions/checkout@v4 - name: Install cibuildwheel # Nb. keep cibuildwheel version pin consistent with job below - run: pipx install cibuildwheel==2.16.5 + run: pipx install cibuildwheel==2.21.3 - id: set-matrix # Once we have the windows build figured out, it can be added here # by updating the matrix to include windows builds as well. @@ -112,7 +112,7 @@ jobs: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v2.16.5 + uses: pypa/cibuildwheel@v2.21.3 with: only: ${{ matrix.only }} env: From a2050130537cc31cae1806a8a3663b4927bab111 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Wed, 30 Oct 2024 22:05:44 -0300 Subject: [PATCH 319/378] Trigger build From 08b3e914ff2acaa3288313de15374355b76ec2d2 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 09:10:54 -0300 Subject: [PATCH 320/378] Bump library versions --- .github/workflows/wheels.yml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index c3aaf48d..85410d98 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -99,6 +99,10 @@ jobs: matrix: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} + env: + PYXMLSEC_LIBXML2_VERSION: 2.12.9 + PYXMLSEC_LIBXSLT_VERSION: 1.1.42 + steps: - name: Check out the repo uses: actions/checkout@v4 From 6a2769179429c17263d45b15e0a53cd05eca9c71 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 09:37:23 -0300 Subject: [PATCH 321/378] Fix sdist workflow --- .github/workflows/sdist.yml | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index e7c0f39d..27985647 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -3,12 +3,15 @@ on: [push, pull_request] jobs: sdist: runs-on: ubuntu-latest + strategy: + matrix: + python: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v3 - - name: Set up Python 3.11 + - name: Set up Python uses: actions/setup-python@v4 with: - python-version: "3.11" + python-version: ${{ matrix.python }} - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel From 9e134cbb915267ebd86b8b876b9f75287be13f75 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 09:39:10 -0300 Subject: [PATCH 322/378] Add missing apt-get update --- .github/workflows/sdist.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 27985647..e987cdce 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -20,6 +20,7 @@ jobs: python setup.py sdist - name: Install test dependencies run: | + sudo apt-get update sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl pip install --upgrade -r requirements-test.txt --no-binary lxml pip install dist/xmlsec-$(python setup.py --version).tar.gz From b5847db453a1a7780aa18f5bcb5cc28811a70ed7 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 09:48:06 -0300 Subject: [PATCH 323/378] Fix linux brew workflow --- .github/workflows/linuxbrew.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 886bd8c9..1fd2358d 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -5,7 +5,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ["3.8", "3.9", "3.10", "3.11"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13"] steps: - uses: actions/checkout@v3 - name: Install brew From 7216b770b6bfc6663bae503c74be3a4108828e05 Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 10:00:56 -0300 Subject: [PATCH 324/378] Install in venv --- .github/workflows/linuxbrew.yml | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 1fd2358d..14acfe94 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -18,19 +18,19 @@ jobs: brew update brew install python@${{ matrix.python }} gcc libxml2 libxmlsec1 pkg-config echo "/home/linuxbrew/.linuxbrew/opt/python@${{ matrix.python }}/libexec/bin" >> $GITHUB_PATH - - name: Install python dependencies + - name: Build wheel run: | + python3 -m venv build_venv + source build_venv/bin/activate pip3 install --upgrade setuptools wheel build - - name: Build linux_x86_64 wheel - run: | export CFLAGS="-I$(brew --prefix)/include" export LDFLAGS="-L$(brew --prefix)/lib" python3 -m build rm -rf build/ - - name: Install test dependencies + - name: Run tests run: | + python3 -m venv test_venv + source test_venv/bin/activate pip3 install --upgrade -r requirements-test.txt pip3 install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ - - name: Run tests - run: | pytest -v --color=yes From f0fa15f3c17c6135bf060e3246e6abe21ae28b1a Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 10:07:40 -0300 Subject: [PATCH 325/378] Make sure we build lxml --- .github/workflows/linuxbrew.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 14acfe94..d8996fd6 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -31,6 +31,6 @@ jobs: run: | python3 -m venv test_venv source test_venv/bin/activate - pip3 install --upgrade -r requirements-test.txt + pip3 install --upgrade --no-binary=lxml -r requirements-test.txt pip3 install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ pytest -v --color=yes From ba1e39c1b02a2fd954c2e8a34ed0b9bd4b69e35f Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 10:22:06 -0300 Subject: [PATCH 326/378] Fix osx workflow --- .github/workflows/macosx.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 6d0548e8..21be9b75 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -5,7 +5,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: [3.5, 3.6, 3.7, 3.8, 3.9, "3.10", "3.11"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13"] static_deps: ["static", ""] steps: - uses: actions/checkout@v3 From 911c537d12ca0296daf89b90513b2efb95b60b6a Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 10:29:12 -0300 Subject: [PATCH 327/378] Build lxml with --no-binary --- .github/workflows/macosx.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 21be9b75..1b82d22d 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -35,7 +35,8 @@ jobs: echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV - name: Install test dependencies run: | - pip install coverage --upgrade -r requirements-test.txt + export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" + pip install coverage --upgrade --no-binary=lxml -r requirements-test.txt pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV - name: Run tests From 413c1af090178b20f7208ddceed1d0a083c336ca Mon Sep 17 00:00:00 2001 From: Jonathan Green Date: Thu, 31 Oct 2024 11:00:34 -0300 Subject: [PATCH 328/378] Ignore macos platforms that lxml no longer supports --- pyproject.toml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/pyproject.toml b/pyproject.toml index 9b6469d4..8c03f910 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -58,6 +58,9 @@ skip = [ "cp37-manylinux_aarch64", "cp36-musllinux_aarch64", "cp37-musllinux_aarch64", + "cp36-macosx*", + "cp37-macosx*", + "cp38-macosx*", ] test-command = "pytest -v --color=yes {package}/tests" before-test = "pip install -r requirements-test.txt" From e634b2ff5bdfd1ca6dec23f11d6d689e818aa0fa Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Tue, 5 Nov 2024 13:53:31 -0500 Subject: [PATCH 329/378] Update: PR#333 https://github.com/xmlsec/python-xmlsec/pull/333 --- .github/workflows/opensuse-tumbleweed.yml | 33 ----------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/opensuse-tumbleweed.yml diff --git a/.github/workflows/opensuse-tumbleweed.yml b/.github/workflows/opensuse-tumbleweed.yml deleted file mode 100644 index 2f4caf49..00000000 --- a/.github/workflows/opensuse-tumbleweed.yml +++ /dev/null @@ -1,33 +0,0 @@ -name: opensuse-tumbleweed -on: [push, pull_request] -jobs: - tumbleweed: - runs-on: ubuntu-latest - container: opensuse/tumbleweed - strategy: - matrix: - python-version: ["3.8", "3.9", "3.10", "3.11"] - steps: - - uses: actions/checkout@v1 - - name: Install build dependencies - run: | - zypper refresh - zypper update - # The follwoing installs "devel_basis" pattern since installing the pattern fails because of few - # incompatibilty issues among packages - zypper -n install autoconf automake binutils bison cpp cpp13 flex gawk gcc gcc13 gdbm-devel gettext-runtime gettext-tools glibc-devel info kbd kbd-legacy libapparmor1 libasan8 libatomic1 libctf-nobfd0 libctf0 libdb-4_8 libfl-devel libfl2 libgdbm6 libgdbm_compat4 libgomp1 libhwasan0 libisl23 libitm1 libkmod2 liblsan0 libltdl7 libmpc3 libmpfr6 libseccomp2 libtextstyle0 libtool libtsan2 libubsan1 libxcrypt-devel libzio1 linux-glibc-devel m4 make makeinfo ncurses-devel pam-config patch perl perl-Text-Unidecode perl-base purge-kernels-service system-user-nobody systemd systemd-default-settings systemd-default-settings-branding-openSUSE systemd-presets-branding-openSUSE systemd-presets-common-SUSE tack update-alternatives zlib-devel - PKGVER_NO_DOT=$(tr -d '.' <<< ${{ matrix.python-version }}) - zypper -n install git libxmlsec1-openssl1 xmlsec1-openssl-devel python${PKGVER_NO_DOT}-devel - python${{ matrix.python-version }} -m venv .venv - .venv/bin/python -m pip install --upgrade pip setuptools wheel - - name: Build linux_x86_64 wheel - run: | - .venv/bin/python setup.py bdist_wheel - rm -rf build/ - - name: Install test dependencies - run: | - .venv/bin/python -m pip install --upgrade --no-binary=lxml -r requirements-test.txt - .venv/bin/python -m pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ - - name: Run tests - run: | - .venv/bin/python -m pytest -v --color=yes From 1104b4cb56078d7753bad9b09428e889ed01f37f Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Tue, 5 Nov 2024 16:12:06 -0500 Subject: [PATCH 330/378] Also support Macports --- README.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/README.rst b/README.rst index 60fb3ea1..bd3a1be9 100644 --- a/README.rst +++ b/README.rst @@ -93,6 +93,12 @@ Mac brew install libxml2 libxmlsec1 pkg-config +or + +.. code-block:: bash + + port install libxml2 xmlsec pkgconfig + Alpine ^^^^^^ From 79e7151c879437a0990d22e08b29bf6438a69691 Mon Sep 17 00:00:00 2001 From: Yusuke Hayashi Date: Mon, 10 Feb 2025 18:17:35 +0900 Subject: [PATCH 331/378] Update enc.c --- src/enc.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/enc.c b/src/enc.c index c2bc94bf..42195dd3 100644 --- a/src/enc.c +++ b/src/enc.c @@ -195,7 +195,7 @@ static PyObject* PyXmlSec_EncryptionContextEncryptBinary(PyObject* self, PyObjec // release the replaced nodes in a way safe for `lxml` static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocumentPtr doc) { - PyXmlSec_LxmlElementPtr* elem; + PyXmlSec_LxmlElementPtr elem; // release the replaced nodes in a way safe for `lxml` xmlNodePtr n = ctx->replacedNodeList; xmlNodePtr nn; @@ -204,7 +204,7 @@ static void PyXmlSec_ClearReplacedNodes(xmlSecEncCtxPtr ctx, PyXmlSec_LxmlDocume PYXMLSEC_DEBUGF("clear replaced node %p", n); nn = n->next; // if n has references, it will not be deleted - elem = (PyXmlSec_LxmlElementPtr*)PyXmlSec_elementFactory(doc, n); + elem = (PyXmlSec_LxmlElementPtr)PyXmlSec_elementFactory(doc, n); if (NULL == elem) xmlFreeNode(n); else From 6498eac71c8074b2311dd3a7e90060260d0bd4c9 Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Tue, 11 Mar 2025 15:47:34 -0400 Subject: [PATCH 332/378] Update w/ latest rev of ext libs --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 85410d98..af3fb57d 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -100,7 +100,7 @@ jobs: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} env: - PYXMLSEC_LIBXML2_VERSION: 2.12.9 + PYXMLSEC_LIBXML2_VERSION: 2.13.5 PYXMLSEC_LIBXSLT_VERSION: 1.1.42 steps: From 967754b6ec084d3ee5baa73ad256cf19f0f231de Mon Sep 17 00:00:00 2001 From: Jim Jagielski Date: Fri, 11 Apr 2025 11:49:01 -0400 Subject: [PATCH 333/378] Ensure we don't use the wheel, which uses older versions of lxml2 --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 014bfe10..3490b822 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -lxml >= 3.8.0, !=4.7.0 +lxml >= 3.8.0, !=4.7.0 --no-binary=lxml From f3f9ba34af99f8c857f9c4f1fe95f8485a0e077f Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Sat, 5 Jul 2025 16:15:16 +0200 Subject: [PATCH 334/378] Revert "Ensure we don't use the wheel, which uses older versions of lxml2" This reverts commit 967754b6ec084d3ee5baa73ad256cf19f0f231de. --- requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/requirements.txt b/requirements.txt index 3490b822..014bfe10 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -lxml >= 3.8.0, !=4.7.0 --no-binary=lxml +lxml >= 3.8.0, !=4.7.0 From 40b755f700b413684abca2d71d78a14c9740cfc7 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Sat, 5 Jul 2025 16:16:24 +0200 Subject: [PATCH 335/378] Update library versions based on lxml 6.0.0 --- .github/workflows/wheels.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index af3fb57d..4303504a 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -100,8 +100,8 @@ jobs: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} env: - PYXMLSEC_LIBXML2_VERSION: 2.13.5 - PYXMLSEC_LIBXSLT_VERSION: 1.1.42 + PYXMLSEC_LIBXML2_VERSION: 2.14.4 + PYXMLSEC_LIBXSLT_VERSION: 1.1.43 steps: - name: Check out the repo From 6e691b36f95b9421ccacf64d6c5ec269bc0a9e43 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Sat, 5 Jul 2025 16:31:28 +0200 Subject: [PATCH 336/378] Enable ripemd60 As suggested in https://github.com/xmlsec/python-xmlsec/issues/344#issuecomment-2894393505 --- setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/setup.py b/setup.py index 92588ebc..c1cdce44 100644 --- a/setup.py +++ b/setup.py @@ -523,6 +523,7 @@ def prepare_static_build(self, build_platform): '--disable-shared', '--disable-gost', '--enable-md5', + '--enable-ripemd160', '--disable-crypto-dl', '--enable-static=yes', '--enable-shared=no', From d6ea8dec42a870a3971b15e83d65c5c08d5664ac Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 00:46:52 +0200 Subject: [PATCH 337/378] Fix failing tests in sdist workflows --- .github/workflows/sdist.yml | 6 +++++- .github/workflows/wheels.yml | 6 +++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index e987cdce..04f22c14 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -2,7 +2,11 @@ name: sdist on: [push, pull_request] jobs: sdist: - runs-on: ubuntu-latest + # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev + # v1.2.39, which has a bug that causes tests/test_pkcs11.py to fail. + # (It thinks the softhsm engine has a public key instead of a private key.) + # libxmlsec1 <=1.2.33 or >=1.2.42 works. TODO: Try 26.04 when available. + runs-on: ubuntu-22.04 strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13"] diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 4303504a..f9294fd3 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -19,7 +19,11 @@ permissions: {} jobs: sdist: - runs-on: ubuntu-latest + # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev + # v1.2.39, which has a bug that causes tests/test_pkcs11.py to fail. + # (It thinks the softhsm engine has a public key instead of a private key.) + # libxmlsec1 <=1.2.33 or >=1.2.42 works. TODO: Try 26.04 when available. + runs-on: ubuntu-22.04 permissions: contents: write From bcd364cdb8e99f49172eaae67b2572ffaa7b4e61 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:09:15 +0200 Subject: [PATCH 338/378] Show stdout in setup.py, not only stderr --- setup.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/setup.py b/setup.py index c1cdce44..d5cf53aa 100644 --- a/setup.py +++ b/setup.py @@ -435,17 +435,17 @@ def prepare_static_build(self, build_platform): openssl_config_cmd.append(cross_compiling.triplet) else: openssl_config_cmd.insert(0, './config') - subprocess.check_output(openssl_config_cmd, cwd=str(openssl_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) - subprocess.check_output( + subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env ) self.info('Building zlib') zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.check_output(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) host_arg = "" if cross_compiling: @@ -453,7 +453,7 @@ def prepare_static_build(self, build_platform): self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -464,14 +464,14 @@ def prepare_static_build(self, build_platform): cwd=str(libiconv_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) - subprocess.check_output( + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env ) self.info('Building LibXML2') libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -486,14 +486,14 @@ def prepare_static_build(self, build_platform): cwd=str(libxml2_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) - subprocess.check_output( + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env ) self.info('Building libxslt') libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -507,8 +507,8 @@ def prepare_static_build(self, build_platform): cwd=str(libxslt_dir), env=env, ) - subprocess.check_output(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) - subprocess.check_output( + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env ) @@ -516,7 +516,7 @@ def prepare_static_build(self, build_platform): ldflags.append('-lpthread') env['LDFLAGS'] = ' '.join(ldflags) xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.check_output( + subprocess.check_call( [ './configure', prefix_arg, @@ -537,13 +537,13 @@ def prepare_static_build(self, build_platform): cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_output( + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_output( + subprocess.check_call( ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env ) From c63a4869f9facc60e810a01c3e1cd32d5d14a810 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:10:56 +0200 Subject: [PATCH 339/378] Download xmlsec1 releases from GitHub The server at www.aleksey.com (Cloudflare?) returns 403 Forbidden errors for some combination of: - missing User-Agent header - GitHub Actions CI runner IP address range - TLS settings (version, cipher suite) used by Python <= 3.9 --- setup.py | 18 ++++++++---------- 1 file changed, 8 insertions(+), 10 deletions(-) diff --git a/setup.py b/setup.py index d5cf53aa..8383db4d 100644 --- a/setup.py +++ b/setup.py @@ -70,22 +70,18 @@ def latest_release_from_gnome_org_cache(url, lib_name): return '{}/{}'.format(url, latest_source) -def latest_release_from_github_api(repo): - api_url = 'https://api.github.com/repos/{}/releases'.format(repo) +def latest_release_json_from_github_api(repo): + api_url = 'https://api.github.com/repos/{}/releases/latest'.format(repo) # if we are running in CI, pass along the GH_TOKEN, so we don't get rate limited token = os.environ.get("GH_TOKEN") if token: log.info("Using GitHub token to avoid rate limiting") - api_releases = make_request(api_url, token, json_response=True) - releases = [r['tarball_url'] for r in api_releases if r['prerelease'] is False and r['draft'] is False] - if not releases: - raise DistutilsError('No release found for {}'.format(repo)) - return releases[0] + return make_request(api_url, token, json_response=True) def latest_openssl_release(): - return latest_release_from_github_api('openssl/openssl') + return latest_release_json_from_github_api('openssl/openssl')['tarball_url'] def latest_zlib_release(): @@ -105,7 +101,9 @@ def latest_libxslt_release(): def latest_xmlsec_release(): - return latest_release_from_html('https://www.aleksey.com/xmlsec/download/', re.compile('xmlsec1-(?P.*).tar.gz')) + assets = latest_release_json_from_github_api('lsh123/xmlsec')['assets'] + (tar_gz,) = [asset for asset in assets if asset['name'].endswith('.tar.gz')] + return tar_gz['browser_download_url'] class CrossCompileInfo: @@ -381,7 +379,7 @@ def prepare_static_build(self, build_platform): url = latest_xmlsec_release() self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {}'.format(url))) else: - url = 'https://www.aleksey.com/xmlsec/download/xmlsec1-{}.tar.gz'.format(self.xmlsec1_version) + url = 'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz'.format(v=self.xmlsec1_version) self.info( '{:10}: {}'.format( 'xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url) From 7f1e1d9a48bcf2475f34ad67d25c5a7c0a0b7700 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:14:49 +0200 Subject: [PATCH 340/378] Fix empty argument to ./configure This solves the warning: configure: WARNING: you should use --build, --host, --target --- setup.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/setup.py b/setup.py index 8383db4d..c70381d9 100644 --- a/setup.py +++ b/setup.py @@ -445,9 +445,9 @@ def prepare_static_build(self, build_platform): subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) - host_arg = "" + host_arg = [] if cross_compiling: - host_arg = '--host={}'.format(cross_compiling.arch) + host_arg = ['--host={}'.format(cross_compiling.arch)] self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) @@ -457,7 +457,7 @@ def prepare_static_build(self, build_platform): prefix_arg, '--disable-dependency-tracking', '--disable-shared', - host_arg, + *host_arg, ], cwd=str(libiconv_dir), env=env, @@ -479,7 +479,7 @@ def prepare_static_build(self, build_platform): '--without-python', '--with-iconv={}'.format(self.prefix_dir), '--with-zlib={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(libxml2_dir), env=env, @@ -500,7 +500,7 @@ def prepare_static_build(self, build_platform): '--without-python', '--without-crypto', '--with-libxml-prefix={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(libxslt_dir), env=env, @@ -530,7 +530,7 @@ def prepare_static_build(self, build_platform): '--with-openssl={}'.format(self.prefix_dir), '--with-libxml={}'.format(self.prefix_dir), '--with-libxslt={}'.format(self.prefix_dir), - host_arg, + *host_arg, ], cwd=str(xmlsec1_dir), env=env, From 9c11b8fbf07131dd4709e0d09af89db64f53af9f Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:16:04 +0200 Subject: [PATCH 341/378] Update wheel availability based on lxml 6.0.0 --- pyproject.toml | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/pyproject.toml b/pyproject.toml index 8c03f910..540f91c1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -54,12 +54,10 @@ skip = [ "*-musllinux_i686", # LXML doesn't publish wheels for these platforms, which makes it # difficult for us to build wheels, so we exclude them. - "cp36-manylinux_aarch64", - "cp37-manylinux_aarch64", - "cp36-musllinux_aarch64", - "cp37-musllinux_aarch64", - "cp36-macosx*", - "cp37-macosx*", + "cp36-*", + "cp37-*", + "cp38-manylinux_aarch64", + "cp38-musllinux_aarch64", "cp38-macosx*", ] test-command = "pytest -v --color=yes {package}/tests" From c3f3df2a301ef3e225448fd417aba9b463519cb4 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:16:36 +0200 Subject: [PATCH 342/378] Fix linuxbrew workflow --- .github/workflows/linuxbrew.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index d8996fd6..c3ede39b 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -6,6 +6,9 @@ jobs: strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + env: + # For some unknown reason, linuxbrew tries to use "gcc-11" by default, which doesn't exist. + CC: gcc steps: - uses: actions/checkout@v3 - name: Install brew From 749da1146a87bb1d574af2df0ab012ac2bd50476 Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:16:52 +0200 Subject: [PATCH 343/378] Fix macosx workflow --- .github/workflows/macosx.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 1b82d22d..f639637e 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -26,6 +26,7 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" + export PYXMLSEC_LIBXML2_VERSION="$(pkg-config --modversion libxml-2.0)" python -m build rm -rf build/ - name: Set environment variables From 4f213157de1fa123b77754f9723709a1ff460c6f Mon Sep 17 00:00:00 2001 From: Tomi Belan Date: Mon, 7 Jul 2025 01:17:13 +0200 Subject: [PATCH 344/378] Fix manylinux workflow --- .github/workflows/manylinux.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index a44776b3..db8ea913 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -5,11 +5,11 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp36-cp36m, cp37-cp37m, cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311] + python-abi: [cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313] image: - manylinux2014_x86_64 - manylinux_2_28_x86_64 - - musllinux_1_1_x86_64 + - musllinux_1_2_x86_64 container: quay.io/pypa/${{ matrix.image }} steps: - uses: actions/checkout@v1 From 8f047912b4a00f5d2f42dc55691d241fbfdd2d53 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 7 Jul 2025 00:16:28 +0000 Subject: [PATCH 345/378] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- setup.py | 16 ++++------------ 1 file changed, 4 insertions(+), 12 deletions(-) diff --git a/setup.py b/setup.py index c70381d9..8d3d4b94 100644 --- a/setup.py +++ b/setup.py @@ -463,9 +463,7 @@ def prepare_static_build(self, build_platform): env=env, ) subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) - subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env) self.info('Building LibXML2') libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) @@ -485,9 +483,7 @@ def prepare_static_build(self, build_platform): env=env, ) subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) - subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env) self.info('Building libxslt') libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) @@ -506,9 +502,7 @@ def prepare_static_build(self, build_platform): env=env, ) subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) - subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env) self.info('Building xmlsec1') ldflags.append('-lpthread') @@ -541,9 +535,7 @@ def prepare_static_build(self, build_platform): cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env - ) + subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env) ext = self.ext_map['xmlsec'] ext.define_macros = [ From 3480dd30526faaf7764b5a674fa739dffa689a20 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 9 Jul 2025 10:07:46 +0200 Subject: [PATCH 346/378] [pre-commit.ci] pre-commit autoupdate (#312) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/psf/black: 24.3.0 → 25.1.0](https://github.com/psf/black/compare/24.3.0...25.1.0) - [github.com/pre-commit/pre-commit-hooks: v4.6.0 → v5.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v4.6.0...v5.0.0) - [github.com/PyCQA/flake8: 7.0.0 → 7.3.0](https://github.com/PyCQA/flake8/compare/7.0.0...7.3.0) - [github.com/PyCQA/isort: 5.13.2 → 6.0.1](https://github.com/PyCQA/isort/compare/5.13.2...6.0.1) - [github.com/pre-commit/mirrors-mypy: v1.9.0 → v1.16.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.9.0...v1.16.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 820778ef..a02d6fac 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,14 +2,14 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/psf/black - rev: 24.3.0 + rev: 25.1.0 hooks: - id: black types: [] files: ^.*.pyi?$ exclude: ^doc/ - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.6.0 + rev: v5.0.0 hooks: - id: no-commit-to-branch - id: trailing-whitespace @@ -25,17 +25,17 @@ repos: - id: pretty-format-json args: [--autofix] - repo: https://github.com/PyCQA/flake8 - rev: 7.0.0 + rev: 7.3.0 hooks: - id: flake8 exclude: ^setup.py$ additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] - repo: https://github.com/PyCQA/isort - rev: 5.13.2 + rev: 6.0.1 hooks: - id: isort - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.9.0 + rev: v1.16.1 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From 8f3d9247259116ed856bcc0e840c1ee644ccefa7 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Thu, 10 Jul 2025 12:34:08 +0200 Subject: [PATCH 347/378] Fix windows wheels and add ARM support (#354) Co-authored-by: Tomi Belan --- .github/workflows/wheels.yml | 2 +- setup.py | 19 +++++++++++-------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f9294fd3..66e6db8f 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -87,7 +87,7 @@ jobs: && cibuildwheel --print-build-identifiers --platform macos \ | jq -nRc '{"only": inputs, "os": "macos-latest"}' \ && cibuildwheel --print-build-identifiers --platform windows \ - | jq -nRc '{"only": inputs, "os": "windows-2019"}' + | jq -nRc '{"only": inputs, "os": "windows-2022"}' } | jq -sc ) echo "include=$MATRIX" diff --git a/setup.py b/setup.py index 8d3d4b94..7c4a2e63 100644 --- a/setup.py +++ b/setup.py @@ -4,6 +4,7 @@ import json import multiprocessing import os +import platform import re import subprocess import sys @@ -211,19 +212,21 @@ def run(self): super(build_ext, self).run() def prepare_static_build_win(self): - release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2024.04.17/' - if sys.maxsize > 2147483647: # 2.0 GiB + release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' + if platform.machine() == 'ARM64': + suffix = 'win-arm64' + elif sys.maxsize > 2**32: # 2.0 GiB suffix = 'win64' else: suffix = 'win32' libs = [ - 'libxml2-2.11.7.{}.zip'.format(suffix), - 'libxslt-1.1.37.{}.zip'.format(suffix), - 'zlib-1.2.12.{}.zip'.format(suffix), - 'iconv-1.16-1.{}.zip'.format(suffix), - 'openssl-3.0.8.{}.zip'.format(suffix), - 'xmlsec-1.3.4.{}.zip'.format(suffix), + 'libxml2-2.11.9-3.{}.zip'.format(suffix), + 'libxslt-1.1.39.{}.zip'.format(suffix), + 'zlib-1.3.1.{}.zip'.format(suffix), + 'iconv-1.18-1.{}.zip'.format(suffix), + 'openssl-3.0.16.pl1.{}.zip'.format(suffix), + 'xmlsec-1.3.7.{}.zip'.format(suffix), ] for libfile in libs: From f7b8507b02fc17b7d96a1b4689ef11012cda8f00 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Thu, 10 Jul 2025 21:13:55 +0200 Subject: [PATCH 348/378] Add Windows ARM wheels support (#355) --- .github/workflows/wheels.yml | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 66e6db8f..ae10888c 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -87,7 +87,9 @@ jobs: && cibuildwheel --print-build-identifiers --platform macos \ | jq -nRc '{"only": inputs, "os": "macos-latest"}' \ && cibuildwheel --print-build-identifiers --platform windows \ - | jq -nRc '{"only": inputs, "os": "windows-2022"}' + | jq -nRc '{"only": inputs, "os": "windows-2022"}' \ + && cibuildwheel --print-build-identifiers --platform windows --archs ARM64 \ + | jq -nRc '{"only": inputs, "os": "windows-11-arm"}' } | jq -sc ) echo "include=$MATRIX" From f09c3c86015d2b97f56d96900cfc02e70aaf5518 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 14 Jul 2025 07:55:53 +0200 Subject: [PATCH 349/378] Convert README format from reStructuredText to markdown (#357) Markdown is much easier to manage and more GitHub compatible. Also updated the badges links and removed deprecated ones. --- .appveyor.yml | 64 -------------- README.md | 198 +++++++++++++++++++++++++++++++++++++++++++ README.rst | 229 -------------------------------------------------- setup.cfg | 2 +- setup.py | 2 +- 5 files changed, 200 insertions(+), 295 deletions(-) delete mode 100644 .appveyor.yml create mode 100644 README.md delete mode 100644 README.rst diff --git a/.appveyor.yml b/.appveyor.yml deleted file mode 100644 index ce025819..00000000 --- a/.appveyor.yml +++ /dev/null @@ -1,64 +0,0 @@ -environment: - matrix: - - python: 35 - - python: 35-x64 - - python: 36 - - python: 36-x64 - - python: 37 - - python: 37-x64 - - python: 38 - - python: 38-x64 - - python: 39 - python_version: 3.9.13 - - python: 39-x64 - python_version: 3.9.13 - - python: 310 - python_version: 3.10.6 - - python: 310-x64 - python_version: 3.10.6 - - python: 311 - python_version: 3.11.2 - - python: 311-x64 - python_version: 3.11.2 - -install: - - ps: | - # from https://github.com/appveyor/build-images/blob/27bde614bc60d7ef7a8bc46182f4d7582fa11b56/scripts/Windows/install_python.ps1#L88-L108 - function InstallPythonEXE($targetPath, $version) { - $urlPlatform = "" - if ($targetPath -match '-x64$') { - $urlPlatform = "-amd64" - } - Write-Host "Installing Python $version$urlPlatform to $($targetPath)..." -ForegroundColor Cyan - $downloadUrl = "https://www.python.org/ftp/python/$version/python-$version$urlPlatform.exe" - Write-Host "Downloading $($downloadUrl)..." - $exePath = "$env:TEMP\python-$version.exe" - (New-Object Net.WebClient).DownloadFile($downloadUrl, $exePath) - Write-Host "Installing..." - cmd /c start /wait $exePath /quiet TargetDir="$targetPath" Shortcuts=0 Include_launcher=1 InstallLauncherAllUsers=1 Include_debug=1 - Remove-Item $exePath - Write-Host "Installed Python $version" -ForegroundColor Green - } - if ( -not ( Test-Path -Path C:\\Python$env:PYTHON -PathType Container ) ) { - InstallPythonEXE C:\\Python$env:PYTHON $env:PYTHON_VERSION - } - - SET PATH=C:\\Python%PYTHON%;c:\\Python%PYTHON%\\scripts;%PATH% - - python -m pip install -U pip wheel setuptools - -build: off -build_script: - - python setup.py bdist_wheel - -test: off -test_script: - - pip install -r requirements-test.txt - - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist - - pytest -v --color=yes --junitxml=unittests.xml - - ps: Get-ChildItem dist\*.whl | % { Push-AppveyorArtifact $_.FullName -FileName $_.Name } - -on_finish: - - ps: | - # archive test results at AppVeyor - $wc = New-Object 'System.Net.WebClient' - $wc.UploadFile("https://ci.appveyor.com/api/testresults/junit/$($env:APPVEYOR_JOB_ID)", (Resolve-Path .\unittests.xml)) - $LastExitCode = 0 diff --git a/README.md b/README.md new file mode 100644 index 00000000..6abd6a5a --- /dev/null +++ b/README.md @@ -0,0 +1,198 @@ +# python-xmlsec + +[![image](https://img.shields.io/pypi/v/xmlsec.svg?logo=python&logoColor=white)](https://pypi.python.org/pypi/xmlsec) +[![pre-commit.ci status](https://results.pre-commit.ci/badge/github/xmlsec/python-xmlsec/master.svg)](https://results.pre-commit.ci/latest/github/xmlsec/python-xmlsec/master) +[![image](https://github.com/xmlsec/python-xmlsec/actions/workflows/manylinux.yml/badge.svg)](https://github.com/xmlsec/python-xmlsec/actions/workflows/manylinux.yml) +[![image](https://github.com/xmlsec/python-xmlsec/actions/workflows/macosx.yml/badge.svg)](https://github.com/xmlsec/python-xmlsec/actions/workflows/macosx.yml) +[![image](https://github.com/xmlsec/python-xmlsec/actions/workflows/linuxbrew.yml/badge.svg)](https://github.com/xmlsec/python-xmlsec/actions/workflows/linuxbrew.yml) +[![image](https://codecov.io/gh/xmlsec/python-xmlsec/branch/master/graph/badge.svg)](https://codecov.io/gh/xmlsec/python-xmlsec) +[![Documentation Status](https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs)](https://xmlsec.readthedocs.io/en/latest/?badge=latest) + +Python bindings for the [XML Security +Library](https://www.aleksey.com/xmlsec/). + +## Documentation + +Documentation for `xmlsec` can be found at +[xmlsec.readthedocs.io](https://xmlsec.readthedocs.io/). + +## Usage + +Check the +[examples](https://xmlsec.readthedocs.io/en/latest/examples.html) +section in the documentation to see various examples of signing and +verifying using the library. + +## Requirements + +- `libxml2 >= 2.9.1` +- `libxmlsec1 >= 1.2.33` + +## Install + +`xmlsec` is available on PyPI: + +``` bash +pip install xmlsec +``` + +Depending on your OS, you may need to install the required native +libraries first: + +### Linux (Debian) + +``` bash +apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl +``` + +Note: There is no required version of LibXML2 for Ubuntu Precise, so you +need to download and install it manually. + +``` bash +wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz +tar -xvf libxml2-2.9.1.tar.gz +cd libxml2-2.9.1 +./configure && make && make install +``` + +### Linux (CentOS) + +``` bash +yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel +``` + +### Linux (Fedora) + +``` bash +dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel +``` + +### Mac + +``` bash +brew install libxml2 libxmlsec1 pkg-config +``` + +or + +``` bash +port install libxml2 xmlsec pkgconfig +``` + +### Alpine + +``` bash +apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec +``` + +## Troubleshooting + +### Mac + +If you get any fatal errors about missing `.h` files, update your +`C_INCLUDE_PATH` environment variable to include the appropriate files +from the `libxml2` and `libxmlsec1` libraries. + +### Windows + +Starting with 1.3.7, prebuilt wheels are available for Windows, so +running `pip install xmlsec` should suffice. If you want to build from +source: + +1. Configure build environment, see + [wiki.python.org](https://wiki.python.org/moin/WindowsCompilers) for + more details. + +2. Install from source dist: + + ``` bash + pip install xmlsec --no-binary=xmlsec + ``` + +## Building from source + +1. Clone the `xmlsec` source code repository to your local computer. + + ``` bash + git clone https://github.com/xmlsec/python-xmlsec.git + ``` + +2. Change into the `python-xmlsec` root directory. + + ``` bash + cd /path/to/xmlsec + ``` + +3. Install the project and all its dependencies using `pip`. + + ``` bash + pip install . + ``` + +## Contributing + +### Setting up your environment + +1. Follow steps 1 and 2 of the [manual installation + instructions](#building-from-source). + +2. Initialize a virtual environment to develop in. This is done so as + to ensure every contributor is working with close-to-identical + versions of packages. + + ``` bash + mkvirtualenv xmlsec + ``` + + The `mkvirtualenv` command is available from `virtualenvwrapper` + package which can be installed by following + [link](http://virtualenvwrapper.readthedocs.org/en/latest/install.html#basic-installation). + +3. Activate the created virtual environment: + + ``` bash + workon xmlsec + ``` + +4. Install `xmlsec` in development mode with testing enabled. This will + download all dependencies required for running the unit tests. + + ``` bash + pip install -r requirements-test.txt + pip install -e "." + ``` + +### Running the test suite + +1. [Set up your environment](#setting-up-your-environment). + +2. Run the unit tests. + + ``` bash + pytest tests + ``` + +3. Tests configuration + + Env variable `PYXMLSEC_TEST_ITERATIONS` specifies number of test + iterations to detect memory leaks. + +### Reporting an issue + +Please attach the output of following information: + +- version of `xmlsec` +- version of `libxmlsec1` +- version of `libxml2` +- output from the command + + ``` bash + pkg-config --cflags xmlsec1 + ``` + +## License + +Unless otherwise noted, all files contained within this project are +licensed under the MIT open source license. See the included `LICENSE` +file or visit [opensource.org](http://opensource.org/licenses/MIT) for +more information. diff --git a/README.rst b/README.rst deleted file mode 100644 index bd3a1be9..00000000 --- a/README.rst +++ /dev/null @@ -1,229 +0,0 @@ -python-xmlsec -============= - -.. image:: https://img.shields.io/pypi/v/xmlsec.svg?logo=python&logoColor=white - :target: https://pypi.python.org/pypi/xmlsec -.. image:: https://results.pre-commit.ci/badge/github/xmlsec/python-xmlsec/master.svg - :target: https://results.pre-commit.ci/latest/github/xmlsec/python-xmlsec/master - :alt: pre-commit.ci status -.. image:: https://img.shields.io/appveyor/ci/hoefling/xmlsec/master.svg?logo=appveyor&logoColor=white&label=AppVeyor - :target: https://ci.appveyor.com/project/hoefling/xmlsec -.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions/workflows/manylinux.yml -.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions/workflows/macosx.yml -.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions/workflows/linuxbrew.yml -.. image:: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml/badge.svg - :target: https://github.com/mehcode/python-xmlsec/actions/workflows/opensuse-tumbleweed.yml -.. image:: https://codecov.io/gh/xmlsec/python-xmlsec/branch/master/graph/badge.svg - :target: https://codecov.io/gh/xmlsec/python-xmlsec -.. image:: https://img.shields.io/readthedocs/xmlsec/latest?logo=read-the-docs - :target: https://xmlsec.readthedocs.io/en/latest/?badge=latest - :alt: Documentation Status - -Python bindings for the `XML Security Library `_. - -Documentation -************* - -A documentation for ``xmlsec`` can be found at `xmlsec.readthedocs.io `_. - -Usage -***** - -Check the `examples `_ section in the documentation to see various examples of signing and verifying using the library. - -Requirements -************ -- ``libxml2 >= 2.9.1`` -- ``libxmlsec1 >= 1.2.33`` - -Install -******* - -``xmlsec`` is available on PyPI: - -.. code-block:: bash - - pip install xmlsec - -Depending on your OS, you may need to install the required native -libraries first: - -Linux (Debian) -^^^^^^^^^^^^^^ - -.. code-block:: bash - - apt-get install pkg-config libxml2-dev libxmlsec1-dev libxmlsec1-openssl - - -Note: There is no required version of LibXML2 for Ubuntu Precise, -so you need to download and install it manually. - -.. code-block:: bash - - wget http://xmlsoft.org/sources/libxml2-2.9.1.tar.gz - tar -xvf libxml2-2.9.1.tar.gz - cd libxml2-2.9.1 - ./configure && make && make install - - -Linux (CentOS) -^^^^^^^^^^^^^^ - -.. code-block:: bash - - yum install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel - - -Linux (Fedora) -^^^^^^^^^^^^^^ - -.. code-block:: bash - - dnf install libxml2-devel xmlsec1-devel xmlsec1-openssl-devel libtool-ltdl-devel - - -Mac -^^^ - -.. code-block:: bash - - brew install libxml2 libxmlsec1 pkg-config - -or - -.. code-block:: bash - - port install libxml2 xmlsec pkgconfig - - -Alpine -^^^^^^ - -.. code-block:: bash - - apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec - - -Troubleshooting -*************** - -Mac -^^^ - -If you get any fatal errors about missing ``.h`` files, update your -``C_INCLUDE_PATH`` environment variable to include the appropriate -files from the ``libxml2`` and ``libxmlsec1`` libraries. - - -Windows -^^^^^^^ - -Starting with 1.3.7, prebuilt wheels are available for Windows, -so running ``pip install xmlsec`` should suffice. If you want -to build from source: - -#. Configure build environment, see `wiki.python.org `_ for more details. - -#. Install from source dist: - - .. code-block:: bash - - pip install xmlsec --no-binary=xmlsec - - -Building from source -******************** - -#. Clone the ``xmlsec`` source code repository to your local computer. - - .. code-block:: bash - - git clone https://github.com/xmlsec/python-xmlsec.git - -#. Change into the ``python-xmlsec`` root directory. - - .. code-block:: bash - - cd /path/to/xmlsec - - -#. Install the project and all its dependencies using ``pip``. - - .. code-block:: bash - - pip install . - - -Contributing -************ - -Setting up your environment -^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -#. Follow steps 1 and 2 of the `manual installation instructions <#building-from-source>`_. - - -#. Initialize a virtual environment to develop in. - This is done so as to ensure every contributor is working with - close-to-identicial versions of packages. - - .. code-block:: bash - - mkvirtualenv xmlsec - - The ``mkvirtualenv`` command is available from ``virtualenvwrapper`` package which can be installed by following `link `_. - -#. Activate the created virtual environment: - - .. code-block:: bash - - workon xmlsec - -#. Install ``xmlsec`` in development mode with testing enabled. - This will download all dependencies required for running the unit tests. - - .. code-block:: bash - - pip install -r requirements-test.txt - pip install -e "." - - -Running the test suite -^^^^^^^^^^^^^^^^^^^^^^ - -#. `Set up your environment <#setting-up-your-environment>`_. - -#. Run the unit tests. - - .. code-block:: bash - - pytest tests - -#. Tests configuration - - Env variable ``PYXMLSEC_TEST_ITERATIONS`` specifies number of - test iterations to detect memory leaks. - -Reporting an issue -^^^^^^^^^^^^^^^^^^ - -Please attach the output of following information: - -* version of ``xmlsec`` -* version of ``libxmlsec1`` -* version of ``libxml2`` -* output from the command - - .. code-block:: bash - - pkg-config --cflags xmlsec1 - -License -******* - -Unless otherwise noted, all files contained within this project are licensed under the MIT opensource license. -See the included ``LICENSE`` file or visit `opensource.org `_ for more information. diff --git a/setup.cfg b/setup.cfg index c090b4e8..7fee05f9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -1,5 +1,5 @@ [metadata] -description_file = README.rst +description_file = README.md [bdist_rpm] release = 1 diff --git a/setup.py b/setup.py index 7c4a2e63..447cebc4 100644 --- a/setup.py +++ b/setup.py @@ -584,7 +584,7 @@ def prepare_static_build(self, build_platform): setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] -with io.open('README.rst', encoding='utf-8') as f: +with io.open('README.md', encoding='utf-8') as f: long_desc = f.read() From 63ab5969bd65be570acb4bca070c46ace4c78b40 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 14 Jul 2025 10:27:30 +0200 Subject: [PATCH 350/378] Drop legacy platform support and improve CI efficiency (#358) Cancelled in-progress GitHub Actions using concurrency groups to reduce CI resource usage. Fully removed support for Python 3.8 and lower. Discontinued building wheels for Linux i686 and Windows 32-bit due to low usage based on PyPI download statistics. --- .github/workflows/linuxbrew.yml | 3 ++ .github/workflows/macosx.yml | 5 ++- .github/workflows/manylinux.yml | 5 ++- .github/workflows/sdist.yml | 3 ++ .github/workflows/wheels.yml | 4 ++ .travis.yml | 79 +++++++++++++++++---------------- pyproject.toml | 21 +++++---- 7 files changed, 68 insertions(+), 52 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index c3ede39b..404321ea 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -1,5 +1,8 @@ name: linuxbrew on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: linuxbrew: runs-on: ubuntu-latest diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index f639637e..7961b5b9 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -1,5 +1,8 @@ -name: MacOS +name: macOS on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: macosx: runs-on: macos-latest diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index db8ea913..9d578f05 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -1,11 +1,14 @@ name: manylinux on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: manylinux: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp38-cp38, cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313] + python-abi: [cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313] image: - manylinux2014_x86_64 - manylinux_2_28_x86_64 diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 04f22c14..3f3eacf0 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -1,5 +1,8 @@ name: sdist on: [push, pull_request] +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true jobs: sdist: # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index ae10888c..6b74c1b6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -15,6 +15,10 @@ on: pull_request: workflow_dispatch: +concurrency: + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: true + permissions: {} jobs: diff --git a/.travis.yml b/.travis.yml index 9e6ca540..9574a1c7 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,51 +1,52 @@ -dist: trusty -sudo: false +dist: focal language: python +travis: + auto_cancel: + push: true + pull_request: true + notifications: email: false -matrix: - include: - - python: 3.5 - - python: 3.6 - - python: 3.7 - dist: xenial - sudo: required - - python: 3.8 - dist: xenial - sudo: required - - python: 3.9 - dist: xenial - sudo: required - - python: 3.11 - dist: xenial - sudo: required + +python: + - "3.9" + - "3.10" + - "3.11" + - "3.12" + - "3.13" + env: global: - - CFLAGS=-coverage - - LDFLAGS=-coverage -lgcov - - PYXMLSEC_TEST_ITERATIONS=50 + - CFLAGS=-coverage + - LDFLAGS=-coverage -lgcov + - PYXMLSEC_TEST_ITERATIONS=50 addons: apt: packages: - - libssl-dev - - libxmlsec1 - - libxmlsec1-dev - - libxmlsec1-openssl - - libxslt1-dev - - pkg-config - - lcov + - libssl-dev + - libxmlsec1 + - libxmlsec1-dev + - libxmlsec1-openssl + - libxslt1-dev + - pkg-config + - lcov + install: -- travis_retry pip install --upgrade pip setuptools wheel -- travis_retry pip install coverage -r requirements-test.txt --upgrade --force-reinstall -- python setup.py bdist_wheel -- pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ -script: coverage run -m pytest -v tests --color=yes + - travis_retry pip install --upgrade pip setuptools wheel + - travis_retry pip install coverage -r requirements-test.txt --upgrade --force-reinstall + - python setup.py bdist_wheel + - pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + +script: + - coverage run -m pytest -v tests --color=yes + after_success: -- lcov --capture --no-external --directory . --output-file coverage.info -- lcov --list coverage.info -- bash <(curl -s https://codecov.io/bash) -f coverage.info + - lcov --capture --no-external --directory . --output-file coverage.info + - lcov --list coverage.info + - bash <(curl -s https://codecov.io/bash) -f coverage.info + before_deploy: -- travis_retry pip install Sphinx -r doc/source/requirements.txt -- git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff -- sphinx-build -EWanb html doc/source build/sphinx + - travis_retry pip install Sphinx -r doc/source/requirements.txt + - git apply --verbose --no-index --unsafe-paths --directory=$(python -c "import site; print(site.getsitepackages()[0])") doc/source/sphinx-pr-6916.diff + - sphinx-build -EWanb html doc/source build/sphinx diff --git a/pyproject.toml b/pyproject.toml index 540f91c1..a0380dcf 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -47,18 +47,17 @@ known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] [tool.cibuildwheel] +build = [ + "cp39-*", + "cp310-*", + "cp311-*", + "cp312-*", + "cp313-*" +] build-verbosity = 1 build-frontend = "build" skip = [ - "pp*", - "*-musllinux_i686", - # LXML doesn't publish wheels for these platforms, which makes it - # difficult for us to build wheels, so we exclude them. - "cp36-*", - "cp37-*", - "cp38-manylinux_aarch64", - "cp38-musllinux_aarch64", - "cp38-macosx*", + "pp*", # Skips PyPy builds (pp38-*, pp39-*, etc.) ] test-command = "pytest -v --color=yes {package}/tests" before-test = "pip install -r requirements-test.txt" @@ -68,7 +67,7 @@ test-skip = "*-macosx_arm64" PYXMLSEC_STATIC_DEPS = "true" [tool.cibuildwheel.linux] -archs = ["x86_64", "aarch64", "i686"] +archs = ["x86_64", "aarch64"] environment-pass = [ "PYXMLSEC_LIBXML2_VERSION", "PYXMLSEC_LIBXSLT_VERSION", @@ -81,7 +80,7 @@ archs = ["x86_64", "arm64"] before-all = "brew install perl" [tool.cibuildwheel.windows] -archs = ["AMD64", "x86"] +archs = ["AMD64"] [[tool.cibuildwheel.overrides]] select = "*-manylinux*" From f43021900f9de3b9fb60f933720d38c06b885d84 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 14 Jul 2025 16:29:06 +0200 Subject: [PATCH 351/378] Migrate linting to Ruff and update CI settings (#359) Replace flake8, black, and isort with Ruff as the unified linter and formatter. - Applied auto-fixes from Ruff - Removed legacy configuration for flake8, black, and isort - Updated CI settings to prevent job cancelation on master --- .github/workflows/linuxbrew.yml | 2 +- .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux.yml | 2 +- .github/workflows/sdist.yml | 2 +- .github/workflows/wheels.yml | 2 +- .pre-commit-config.yaml | 84 +++++++-------- doc/source/conf.py | 25 +++-- doc/source/examples/decrypt.py | 4 +- doc/source/examples/encrypt.py | 24 ++--- doc/source/examples/verify.py | 2 +- pyproject.toml | 88 +++++++++++----- requirements-test.txt | 6 +- requirements.txt | 2 +- setup.cfg | 19 ++-- setup.py | 178 ++++++++++++++------------------ src/xmlsec/constants.pyi | 7 +- tests/base.py | 32 +++--- tests/conftest.py | 3 +- tests/softhsm_setup.py | 26 ++--- tests/test_constants.py | 8 +- tests/test_doc_examples.py | 14 +-- tests/test_ds.py | 110 ++++++++++---------- tests/test_enc.py | 50 ++++----- tests/test_keys.py | 120 +++++++++++---------- tests/test_main.py | 12 +-- tests/test_pkcs11.py | 8 +- tests/test_templates.py | 88 ++++++++-------- tests/test_tree.py | 10 +- tests/test_type_stubs.py | 8 +- tests/test_xmlsec.py | 3 +- 30 files changed, 460 insertions(+), 481 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 404321ea..8a231047 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -2,7 +2,7 @@ name: linuxbrew on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' }} jobs: linuxbrew: runs-on: ubuntu-latest diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 7961b5b9..44d214bc 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -2,7 +2,7 @@ name: macOS on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' }} jobs: macosx: runs-on: macos-latest diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 9d578f05..357e93eb 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -2,7 +2,7 @@ name: manylinux on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' }} jobs: manylinux: runs-on: ubuntu-latest diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 3f3eacf0..3bdc9764 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -2,7 +2,7 @@ name: sdist on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' }} jobs: sdist: # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 6b74c1b6..62d48b4b 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -17,7 +17,7 @@ on: concurrency: group: ${{ github.workflow }}-${{ github.ref }} - cancel-in-progress: true + cancel-in-progress: ${{ github.ref_name != 'master' }} permissions: {} diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index a02d6fac..48abcc6f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,48 +1,42 @@ # See https://pre-commit.com for more information # See https://pre-commit.com/hooks.html for more hooks repos: -- repo: https://github.com/psf/black - rev: 25.1.0 - hooks: - - id: black - types: [] - files: ^.*.pyi?$ - exclude: ^doc/ -- repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 - hooks: - - id: no-commit-to-branch - - id: trailing-whitespace - - id: end-of-file-fixer - - id: check-yaml - - id: check-added-large-files - - id: check-ast - - id: check-merge-conflict - - id: check-json - - id: detect-private-key - exclude: ^.*/rsakey.pem$ - - id: mixed-line-ending - - id: pretty-format-json - args: [--autofix] -- repo: https://github.com/PyCQA/flake8 - rev: 7.3.0 - hooks: - - id: flake8 - exclude: ^setup.py$ - additional_dependencies: [flake8-docstrings, flake8-bugbear, flake8-logging-format, flake8-builtins, flake8-eradicate, flake8-fixme, pep8-naming, flake8-pep3101, flake8-annotations-complexity,flake8-pyi] -- repo: https://github.com/PyCQA/isort - rev: 6.0.1 - hooks: - - id: isort -- repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.1 - hooks: - - id: mypy - exclude: (setup.py|tests/.*.py|doc/.*) - types: [] - files: ^.*.pyi?$ - additional_dependencies: [lxml-stubs,types-docutils] -- repo: https://github.com/pre-commit/pygrep-hooks - rev: v1.10.0 - hooks: - - id: rst-backticks +- repo: https://github.com/astral-sh/ruff-pre-commit + rev: v0.12.3 + hooks: + - id: ruff + args: ["--fix"] + types: [python] + - id: ruff-format + types: [python] + +- repo: https://github.com/pre-commit/pre-commit-hooks + rev: v5.0.0 + hooks: + - id: no-commit-to-branch + - id: trailing-whitespace + - id: end-of-file-fixer + - id: check-yaml + - id: check-added-large-files + - id: check-ast + - id: check-merge-conflict + - id: check-json + - id: detect-private-key + exclude: ^.*/rsakey.pem$ + - id: mixed-line-ending + - id: pretty-format-json + args: [--autofix] + +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.16.1 + hooks: + - id: mypy + exclude: (setup.py|tests/.*.py|doc/.*) + types: [] + files: ^.*.pyi?$ + additional_dependencies: [lxml-stubs, types-docutils] + +- repo: https://github.com/pre-commit/pygrep-hooks + rev: v1.10.0 + hooks: + - id: rst-backticks diff --git a/doc/source/conf.py b/doc/source/conf.py index 35329050..900b79da 100644 --- a/doc/source/conf.py +++ b/doc/source/conf.py @@ -19,12 +19,12 @@ source_suffix = '.rst' master_doc = 'index' -project = u'python-xmlsec' -copyright = u'2020, Oleg Hoefling ' # noqa: A001 -author = u'Bulat Gaifullin ' +project = 'python-xmlsec' +copyright = '2020, Oleg Hoefling ' +author = 'Bulat Gaifullin ' release = importlib.metadata.version('xmlsec') parsed: Version = parse(release) -version = '{}.{}'.format(parsed.major, parsed.minor) +version = f'{parsed.major}.{parsed.minor}' exclude_patterns: list[str] = [] pygments_style = 'sphinx' @@ -39,19 +39,19 @@ ( master_doc, 'python-xmlsec.tex', - u'python-xmlsec Documentation', - u'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}', + 'python-xmlsec Documentation', + 'Bulat Gaifullin \\textless{}gaifullinbf@gmail.com\\textgreater{}', 'manual', ) ] -man_pages = [(master_doc, 'python-xmlsec', u'python-xmlsec Documentation', [author], 1)] +man_pages = [(master_doc, 'python-xmlsec', 'python-xmlsec Documentation', [author], 1)] texinfo_documents = [ ( master_doc, 'python-xmlsec', - u'python-xmlsec Documentation', + 'python-xmlsec Documentation', author, 'python-xmlsec', 'One line description of project.', @@ -63,10 +63,10 @@ autodoc_docstring_signature = True -rst_prolog = ''' +rst_prolog = """ .. role:: xml(code) :language: xml -''' +""" # LXML crossref'ing stuff: # LXML doesn't have an intersphinx docs, @@ -75,8 +75,7 @@ def lxml_element_doc_reference(app: Sphinx, env: BuildEnvironment, node: pending_xref, contnode: Text) -> reference: - """ - Handle a missing reference only if it is a ``lxml.etree._Element`` ref. + """Handle a missing reference only if it is a ``lxml.etree._Element`` ref. We handle only :class:`lxml.etree._Element` and :class:`~lxml.etree._Element` nodes. """ @@ -85,7 +84,7 @@ def lxml_element_doc_reference(app: Sphinx, env: BuildEnvironment, node: pending and node.get('reftarget', None) == 'lxml.etree._Element' and contnode.astext() in ('lxml.etree._Element', '_Element') ): - reftitle = '(in lxml v{})'.format(lxml.__version__) # type: ignore[attr-defined] + reftitle = f'(in lxml v{lxml.__version__})' # type: ignore[attr-defined] newnode = reference('', '', internal=False, refuri=lxml_element_cls_doc_uri, reftitle=reftitle) newnode.append(contnode) return newnode diff --git a/doc/source/examples/decrypt.py b/doc/source/examples/decrypt.py index e107756f..cb474d22 100644 --- a/doc/source/examples/decrypt.py +++ b/doc/source/examples/decrypt.py @@ -6,7 +6,7 @@ key = xmlsec.Key.from_file('rsakey.pem', xmlsec.constants.KeyDataFormatPem) manager.add_key(key) enc_ctx = xmlsec.EncryptionContext(manager) -root = etree.parse("enc1-res.xml").getroot() -enc_data = xmlsec.tree.find_child(root, "EncryptedData", xmlsec.constants.EncNs) +root = etree.parse('enc1-res.xml').getroot() +enc_data = xmlsec.tree.find_child(root, 'EncryptedData', xmlsec.constants.EncNs) decrypted = enc_ctx.decrypt(enc_data) print(etree.tostring(decrypted)) diff --git a/doc/source/examples/encrypt.py b/doc/source/examples/encrypt.py index 98f63b6f..2a92264e 100644 --- a/doc/source/examples/encrypt.py +++ b/doc/source/examples/encrypt.py @@ -9,11 +9,11 @@ template, xmlsec.constants.TransformAes128Cbc, type=xmlsec.constants.TypeEncElement, - ns="xenc", + ns='xenc', ) xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) -key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") +key_info = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') enc_key = xmlsec.template.add_encrypted_key(key_info, xmlsec.constants.TransformRsaOaep) xmlsec.template.encrypted_data_ensure_cipher_value(enc_key) data = template.find('./Data') @@ -24,20 +24,10 @@ manager.add_key(key) enc_ctx = xmlsec.EncryptionContext(manager) -enc_ctx.key = xmlsec.Key.generate( - xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession -) +enc_ctx.key = xmlsec.Key.generate(xmlsec.constants.KeyDataAes, 128, xmlsec.constants.KeyDataTypeSession) enc_data = enc_ctx.encrypt_xml(enc_data, data) -enc_method = xmlsec.tree.find_child( - enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs -) -key_info = xmlsec.tree.find_child( - enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs -) -enc_method = xmlsec.tree.find_node( - key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs -) -cipher_value = xmlsec.tree.find_node( - key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs -) +enc_method = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) +key_info = xmlsec.tree.find_child(enc_data, xmlsec.constants.NodeKeyInfo, xmlsec.constants.DSigNs) +enc_method = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeEncryptionMethod, xmlsec.constants.EncNs) +cipher_value = xmlsec.tree.find_node(key_info, xmlsec.constants.NodeCipherValue, xmlsec.constants.EncNs) print(etree.tostring(cipher_value)) diff --git a/doc/source/examples/verify.py b/doc/source/examples/verify.py index 808a53c2..c3240c99 100644 --- a/doc/source/examples/verify.py +++ b/doc/source/examples/verify.py @@ -5,7 +5,7 @@ with open('sign1-res.xml') as fp: template = etree.parse(fp).getroot() -xmlsec.tree.add_ids(template, ["ID"]) +xmlsec.tree.add_ids(template, ['ID']) signature_node = xmlsec.tree.find_node(template, xmlsec.constants.NodeSignature) # Create a digital signature context (no key manager is needed). ctx = xmlsec.SignatureContext() diff --git a/pyproject.toml b/pyproject.toml index a0380dcf..bb0c459e 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,3 +1,6 @@ +[build-system] +requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4", "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] + [tool.mypy] files = ['src'] ignore_missing_imports = false @@ -19,32 +22,71 @@ warn_no_return = true no_implicit_reexport = true show_error_codes = true -[tool.black] -line_length = 130 -skip-string-normalization = true -target_version = ['py39'] -include = '\.pyi?$' -exclude = ''' +[tool.ruff] +# Maximum line length, same as your original Black + Flake8 config +line-length = 130 + +# Target Python version (used for autofixes and style rules) +target-version = "py39" -( - /( - \.eggs # exclude a few common directories in the - | \.git # root of the project - | \.mypy_cache - | \.tox - | build - | dist - )/ -) -''' +# Directories and files to exclude from linting and formatting +exclude = [ + ".venv*", # virtual environments + ".git", # git directory + "build", # build output + "dist", # distribution packages + "libs", # vendor libraries + ".eggs", # setuptools egg folders + ".direnv*", # direnv environments + "*_pb2.pyi" # protobuf-generated type stubs +] -[tool.isort] -profile = 'black' -known_first_party = ['xmlsec'] -known_third_party = ['lxml', 'pytest', '_pytest', 'hypothesis'] +[tool.ruff.lint] +# Enable rule categories: +# E = pycodestyle (style issues, like indentation, whitespace, etc.) +# F = pyflakes (unused imports, undefined names) +# I = isort (import sorting) +# B = flake8-bugbear (common bugs & anti-patterns) +# UP = pyupgrade (auto-upgrade syntax for newer Python) +# SIM = flake8-simplify (simplifiable code patterns) +# RUF = Ruff-native rules (extra, performance-optimized checks) +select = ["E", "F", "I", "B", "UP", "SIM", "RUF"] +# TODO: Add more rule categories as needed, e.g.: +# D = pydocstyle (docstring format/style issues) -[build-system] -requires = ['setuptools>=42', 'wheel', 'setuptools_scm[toml]>=3.4', "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] +[tool.ruff.lint.per-file-ignores] +"*.pyi" = [ + # Ignore formatting and import errors in stub files + "E301", # expected 1 blank line, found 0 + "E302", # expected 2 blank lines, found 1 + "E305", # expected 2 blank lines after class or function + "E501", # line too long + "E701", # multiple statements on one line + "F401", # unused import + "F811", # redefinition of unused name + "F822" # undefined name in `__all__` +] +"doc/source/conf.py" = [ + "D1" # missing docstring in public module/class/function +] +"doc/source/examples/*.py" = [ + "D1", # allow missing docstrings in examples + "E501" # allow long lines in code examples +] +"tests/*.py" = [ + "D1" # allow missing docstrings in test files +] + +[tool.ruff.format] +# Always use single quotes (e.g., 'text' instead of "text") +quote-style = "single" + +# Format code with or without trailing commas +# true = prefer trailing commas where valid +skip-magic-trailing-comma = false + +# Enforce Unix-style line endings (LF) +line-ending = "lf" [tool.cibuildwheel] build = [ diff --git a/requirements-test.txt b/requirements-test.txt index eb543402..52a31f00 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -1,3 +1,5 @@ -r requirements.txt -pytest>=4.6.9 -lxml-stubs + +pytest==8.4.1 +lxml-stubs==0.5.1 +ruff[format]==0.12.3 diff --git a/requirements.txt b/requirements.txt index 014bfe10..7aa6718b 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -lxml >= 3.8.0, !=4.7.0 +lxml==6.0.0 diff --git a/setup.cfg b/setup.cfg index 7fee05f9..8762c654 100644 --- a/setup.cfg +++ b/setup.cfg @@ -12,14 +12,11 @@ source-dir = doc/source build-dir = doc/build all_files = 1 -[upload_docs] -upload_dir = doc/build/html - -[flake8] -per-file-ignores = - *.pyi: E301, E302, E305, E501, E701, F401, F822 - doc/source/conf.py: D1 - doc/source/examples/*.py: D1, E501 - tests/*.py: D1 -exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv* -max-line-length = 130 +# [flake8] +# per-file-ignores = +# *.pyi: E301, E302, E305, E501, E701, F401, F822 +# doc/source/conf.py: D1 +# doc/source/examples/*.py: D1, E501 +# tests/*.py: D1 +# exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv* +# max-line-length = 130 diff --git a/setup.py b/setup.py index 447cebc4..94b49aa8 100644 --- a/setup.py +++ b/setup.py @@ -1,6 +1,5 @@ import contextlib import html.parser -import io import json import multiprocessing import os @@ -36,7 +35,7 @@ def handle_starttag(self, tag, attrs): def make_request(url, github_token=None, json_response=False): headers = {'User-Agent': 'https://github.com/xmlsec/python-xmlsec'} if github_token: - headers['authorization'] = "Bearer " + github_token + headers['authorization'] = 'Bearer ' + github_token request = Request(url, headers=headers) with contextlib.closing(urlopen(request)) as r: charset = r.headers.get_content_charset() or 'utf-8' @@ -60,24 +59,24 @@ def comp(text): return Version('0.0') latest = max(hrefs, key=comp) - return '{}/{}'.format(url, latest) + return f'{url}/{latest}' def latest_release_from_gnome_org_cache(url, lib_name): - cache_url = '{}/cache.json'.format(url) + cache_url = f'{url}/cache.json' cache = make_request(cache_url, json_response=True) latest_version = cache[2][lib_name][-1] latest_source = cache[1][lib_name][latest_version]['tar.xz'] - return '{}/{}'.format(url, latest_source) + return f'{url}/{latest_source}' def latest_release_json_from_github_api(repo): - api_url = 'https://api.github.com/repos/{}/releases/latest'.format(repo) + api_url = f'https://api.github.com/repos/{repo}/releases/latest' # if we are running in CI, pass along the GH_TOKEN, so we don't get rate limited - token = os.environ.get("GH_TOKEN") + token = os.environ.get('GH_TOKEN') if token: - log.info("Using GitHub token to avoid rate limiting") + log.info('Using GitHub token to avoid rate limiting') return make_request(api_url, token, json_response=True) @@ -115,7 +114,7 @@ def __init__(self, host, arch, compiler): @property def triplet(self): - return "{}-{}-{}".format(self.host, self.arch, self.compiler) + return f'{self.host}-{self.arch}-{self.compiler}' class build_ext(build_ext_orig): @@ -129,7 +128,7 @@ def run(self): self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True) if self.static or sys.platform == 'win32': - self.info('starting static build on {}'.format(sys.platform)) + self.info(f'starting static build on {sys.platform}') buildroot = Path('build', 'tmp') self.prefix_dir = buildroot / 'prefix' @@ -145,19 +144,17 @@ def run(self): if sys.platform == 'win32': self.prepare_static_build_win() - elif 'linux' in sys.platform: - self.prepare_static_build(sys.platform) - elif 'darwin' in sys.platform: + elif 'linux' in sys.platform or 'darwin' in sys.platform: self.prepare_static_build(sys.platform) else: import pkgconfig try: config = pkgconfig.parse('xmlsec1') - except EnvironmentError: - raise DistutilsError('Unable to invoke pkg-config.') - except pkgconfig.PackageNotFoundError: - raise DistutilsError('xmlsec1 is not installed or not in path.') + except OSError as e: + raise DistutilsError('Unable to invoke pkg-config.') from e + except pkgconfig.PackageNotFoundError as e: + raise DistutilsError('xmlsec1 is not installed or not in path.') from e if config is None or not config.get('libraries'): raise DistutilsError('Bad or incomplete result returned from pkg-config.') @@ -178,7 +175,7 @@ def run(self): for key, value in ext.define_macros: if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')): ext.define_macros.remove((key, value)) - ext.define_macros.append((key, '"{0}"'.format(value))) + ext.define_macros.append((key, f'"{value}"')) break if sys.platform == 'win32': @@ -209,7 +206,7 @@ def run(self): else: ext.extra_compile_args.append('-Os') - super(build_ext, self).run() + super().run() def prepare_static_build_win(self): release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' @@ -221,21 +218,21 @@ def prepare_static_build_win(self): suffix = 'win32' libs = [ - 'libxml2-2.11.9-3.{}.zip'.format(suffix), - 'libxslt-1.1.39.{}.zip'.format(suffix), - 'zlib-1.3.1.{}.zip'.format(suffix), - 'iconv-1.18-1.{}.zip'.format(suffix), - 'openssl-3.0.16.pl1.{}.zip'.format(suffix), - 'xmlsec-1.3.7.{}.zip'.format(suffix), + f'libxml2-2.11.9-3.{suffix}.zip', + f'libxslt-1.1.39.{suffix}.zip', + f'zlib-1.3.1.{suffix}.zip', + f'iconv-1.18-1.{suffix}.zip', + f'openssl-3.0.16.pl1.{suffix}.zip', + f'xmlsec-1.3.7.{suffix}.zip', ] for libfile in libs: url = urljoin(release_url, libfile) destfile = self.libs_dir / libfile if destfile.is_file(): - self.info('Using local copy of "{}"'.format(url)) + self.info(f'Using local copy of "{url}"') else: - self.info('Retrieving "{}" to "{}"'.format(url, destfile)) + self.info(f'Retrieving "{url}" to "{destfile}"') urlcleanup() # work around FTP bug 27973 in Py2.7.12+ urlretrieve(url, str(destfile)) @@ -296,9 +293,9 @@ def prepare_static_build(self, build_platform): openssl_tar = self.libs_dir / 'openssl.tar.gz' if self.openssl_version is None: url = latest_openssl_release() - self.info('{:10}: {}'.format('OpenSSL', 'PYXMLSEC_OPENSSL_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('OpenSSL', f'PYXMLSEC_OPENSSL_VERSION unset, downloading latest from {url}')) else: - url = 'https://api.github.com/repos/openssl/openssl/tarball/openssl-{}'.format(self.openssl_version) + url = f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{self.openssl_version}' self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) urlretrieve(url, str(openssl_tar)) @@ -309,12 +306,10 @@ def prepare_static_build(self, build_platform): zlib_tar = self.libs_dir / 'zlib.tar.gz' if self.zlib_version is None: url = latest_zlib_release() - self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_ZLIB_VERSION unset, downloading latest from {url}')) else: - url = 'https://zlib.net/fossils/zlib-{}.tar.gz'.format(self.zlib_version) - self.info( - '{:10}: {}'.format('zlib', 'PYXMLSEC_ZLIB_VERSION={}, downloading from {}'.format(self.zlib_version, url)) - ) + url = f'https://zlib.net/fossils/zlib-{self.zlib_version}.tar.gz' + self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_ZLIB_VERSION={self.zlib_version}, downloading from {url}')) urlretrieve(url, str(zlib_tar)) # fetch libiconv @@ -324,13 +319,11 @@ def prepare_static_build(self, build_platform): libiconv_tar = self.libs_dir / 'libiconv.tar.gz' if self.libiconv_version is None: url = latest_libiconv_release() - self.info('{:10}: {}'.format('zlib', 'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {url}')) else: - url = 'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{}.tar.gz'.format(self.libiconv_version) + url = f'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{self.libiconv_version}.tar.gz' self.info( - '{:10}: {}'.format( - 'zlib', 'PYXMLSEC_LIBICONV_VERSION={}, downloading from {}'.format(self.libiconv_version, url) - ) + '{:10}: {}'.format('zlib', f'PYXMLSEC_LIBICONV_VERSION={self.libiconv_version}, downloading from {url}') ) urlretrieve(url, str(libiconv_tar)) @@ -340,16 +333,12 @@ def prepare_static_build(self, build_platform): self.info('{:10}: {}'.format('libxml2', 'source tar not found, downloading ...')) if self.libxml2_version is None: url = latest_libxml2_release() - self.info('{:10}: {}'.format('libxml2', 'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('libxml2', f'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {url}')) else: version_prefix, _ = self.libxml2_version.rsplit('.', 1) - url = 'https://download.gnome.org/sources/libxml2/{}/libxml2-{}.tar.xz'.format( - version_prefix, self.libxml2_version - ) + url = f'https://download.gnome.org/sources/libxml2/{version_prefix}/libxml2-{self.libxml2_version}.tar.xz' self.info( - '{:10}: {}'.format( - 'libxml2', 'PYXMLSEC_LIBXML2_VERSION={}, downloading from {}'.format(self.libxml2_version, url) - ) + '{:10}: {}'.format('libxml2', f'PYXMLSEC_LIBXML2_VERSION={self.libxml2_version}, downloading from {url}') ) libxml2_tar = self.libs_dir / 'libxml2.tar.xz' urlretrieve(url, str(libxml2_tar)) @@ -360,16 +349,12 @@ def prepare_static_build(self, build_platform): self.info('{:10}: {}'.format('libxslt', 'source tar not found, downloading ...')) if self.libxslt_version is None: url = latest_libxslt_release() - self.info('{:10}: {}'.format('libxslt', 'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('libxslt', f'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {url}')) else: version_prefix, _ = self.libxslt_version.rsplit('.', 1) - url = 'https://download.gnome.org/sources/libxslt/{}/libxslt-{}.tar.xz'.format( - version_prefix, self.libxslt_version - ) + url = f'https://download.gnome.org/sources/libxslt/{version_prefix}/libxslt-{self.libxslt_version}.tar.xz' self.info( - '{:10}: {}'.format( - 'libxslt', 'PYXMLSEC_LIBXSLT_VERSION={}, downloading from {}'.format(self.libxslt_version, url) - ) + '{:10}: {}'.format('libxslt', f'PYXMLSEC_LIBXSLT_VERSION={self.libxslt_version}, downloading from {url}') ) libxslt_tar = self.libs_dir / 'libxslt.tar.gz' urlretrieve(url, str(libxslt_tar)) @@ -380,26 +365,24 @@ def prepare_static_build(self, build_platform): self.info('{:10}: {}'.format('xmlsec1', 'source tar not found, downloading ...')) if self.xmlsec1_version is None: url = latest_xmlsec_release() - self.info('{:10}: {}'.format('xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {}'.format(url))) + self.info('{:10}: {}'.format('xmlsec1', f'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {url}')) else: - url = 'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz'.format(v=self.xmlsec1_version) + url = f'https://github.com/lsh123/xmlsec/releases/download/{self.xmlsec1_version}/xmlsec1-{self.xmlsec1_version}.tar.gz' self.info( - '{:10}: {}'.format( - 'xmlsec1', 'PYXMLSEC_XMLSEC1_VERSION={}, downloading from {}'.format(self.xmlsec1_version, url) - ) + '{:10}: {}'.format('xmlsec1', f'PYXMLSEC_XMLSEC1_VERSION={self.xmlsec1_version}, downloading from {url}') ) xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' urlretrieve(url, str(xmlsec1_tar)) for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): - self.info('Unpacking {}'.format(file.name)) + self.info(f'Unpacking {file.name}') try: with tarfile.open(str(file)) as tar: tar.extractall(path=str(self.build_libs_dir)) - except EOFError: - raise DistutilsError('Bad {} downloaded; remove it and try again.'.format(file.name)) + except EOFError as e: + raise DistutilsError(f'Bad {file.name} downloaded; remove it and try again.') from e - prefix_arg = '--prefix={}'.format(self.prefix_dir) + prefix_arg = f'--prefix={self.prefix_dir}' env = os.environ.copy() cflags = [] @@ -416,14 +399,13 @@ def prepare_static_build(self, build_platform): arch = self.plat_name.rsplit('-', 1)[1] if arch != platform.machine() and arch in ('x86_64', 'arm64'): - self.info('Cross-compiling for {}'.format(arch)) - cflags.append('-arch {}'.format(arch)) - ldflags.append('-arch {}'.format(arch)) + self.info(f'Cross-compiling for {arch}') + cflags.append(f'-arch {arch}') + ldflags.append(f'-arch {arch}') cross_compiling = CrossCompileInfo('darwin64', arch, 'cc') - major_version, minor_version = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) - if major_version >= 11: - if 'MACOSX_DEPLOYMENT_TARGET' not in env: - env['MACOSX_DEPLOYMENT_TARGET'] = "11.0" + major_version, _ = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) + if major_version >= 11 and 'MACOSX_DEPLOYMENT_TARGET' not in env: + env['MACOSX_DEPLOYMENT_TARGET'] = '11.0' env['CFLAGS'] = ' '.join(cflags) env['LDFLAGS'] = ' '.join(ldflags) @@ -437,20 +419,18 @@ def prepare_static_build(self, build_platform): else: openssl_config_cmd.insert(0, './config') subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(openssl_dir), env=env) - subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install_sw'], cwd=str(openssl_dir), env=env - ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install_sw'], cwd=str(openssl_dir), env=env) self.info('Building zlib') zlib_dir = next(self.build_libs_dir.glob('zlib-*')) subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(zlib_dir), env=env) host_arg = [] if cross_compiling: - host_arg = ['--host={}'.format(cross_compiling.arch)] + host_arg = [f'--host={cross_compiling.arch}'] self.info('Building libiconv') libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) @@ -465,8 +445,8 @@ def prepare_static_build(self, build_platform): cwd=str(libiconv_dir), env=env, ) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libiconv_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libiconv_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libiconv_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libiconv_dir), env=env) self.info('Building LibXML2') libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) @@ -478,15 +458,15 @@ def prepare_static_build(self, build_platform): '--disable-shared', '--without-lzma', '--without-python', - '--with-iconv={}'.format(self.prefix_dir), - '--with-zlib={}'.format(self.prefix_dir), + f'--with-iconv={self.prefix_dir}', + f'--with-zlib={self.prefix_dir}', *host_arg, ], cwd=str(libxml2_dir), env=env, ) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxml2_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxml2_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxml2_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxml2_dir), env=env) self.info('Building libxslt') libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) @@ -498,14 +478,14 @@ def prepare_static_build(self, build_platform): '--disable-shared', '--without-python', '--without-crypto', - '--with-libxml-prefix={}'.format(self.prefix_dir), + f'--with-libxml-prefix={self.prefix_dir}', *host_arg, ], cwd=str(libxslt_dir), env=env, ) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1)], cwd=str(libxslt_dir), env=env) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(libxslt_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxslt_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxslt_dir), env=env) self.info('Building xmlsec1') ldflags.append('-lpthread') @@ -524,21 +504,24 @@ def prepare_static_build(self, build_platform): '--enable-shared=no', '--enable-static-linking=yes', '--with-default-crypto=openssl', - '--with-openssl={}'.format(self.prefix_dir), - '--with-libxml={}'.format(self.prefix_dir), - '--with-libxslt={}'.format(self.prefix_dir), + f'--with-openssl={self.prefix_dir}', + f'--with-libxml={self.prefix_dir}', + f'--with-libxslt={self.prefix_dir}', *host_arg, ], cwd=str(xmlsec1_dir), env=env, ) + include_flags = [ + f'-I{self.prefix_dir / "include"}', + f'-I{self.prefix_dir / "include" / "libxml"}', + ] subprocess.check_call( - ['make', '-j{}'.format(multiprocessing.cpu_count() + 1)] - + ['-I{}'.format(str(self.prefix_dir / 'include')), '-I{}'.format(str(self.prefix_dir / 'include' / 'libxml'))], + ['make', f'-j{multiprocessing.cpu_count() + 1}', *include_flags], cwd=str(xmlsec1_dir), env=env, ) - subprocess.check_call(['make', '-j{}'.format(multiprocessing.cpu_count() + 1), 'install'], cwd=str(xmlsec1_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(xmlsec1_dir), env=env) ext = self.ext_map['xmlsec'] ext.define_macros = [ @@ -584,7 +567,7 @@ def prepare_static_build(self, build_platform): setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] -with io.open('README.md', encoding='utf-8') as f: +with open('README.md', encoding='utf-8') as f: long_desc = f.read() @@ -596,10 +579,10 @@ def prepare_static_build(self, build_platform): long_description_content_type='text/markdown', ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, - python_requires='>=3.5', + python_requires='>=3.9', setup_requires=setup_reqs, install_requires=['lxml>=3.8'], - author="Bulat Gaifullin", + author='Bulat Gaifullin', author_email='support@mehcode.com', maintainer='Oleg Hoefling', maintainer_email='oleg.hoefling@gmail.com', @@ -619,12 +602,11 @@ def prepare_static_build(self, build_platform): 'Operating System :: OS Independent', 'Programming Language :: C', 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.5', - 'Programming Language :: Python :: 3.6', - 'Programming Language :: Python :: 3.7', - 'Programming Language :: Python :: 3.8', 'Programming Language :: Python :: 3.9', + 'Programming Language :: Python :: 3.10', 'Programming Language :: Python :: 3.11', + 'Programming Language :: Python :: 3.12', + 'Programming Language :: Python :: 3.13', 'Topic :: Text Processing :: Markup :: XML', 'Typing :: Typed', ], diff --git a/src/xmlsec/constants.pyi b/src/xmlsec/constants.pyi index 3c3ea94f..a9254ddd 100644 --- a/src/xmlsec/constants.pyi +++ b/src/xmlsec/constants.pyi @@ -1,10 +1,5 @@ import sys -from typing import NamedTuple - -if sys.version_info >= (3, 8): - from typing import Final -else: - from typing_extensions import Final +from typing import Final, NamedTuple class __KeyData(NamedTuple): # __KeyData type href: str diff --git a/tests/base.py b/tests/base.py index 48aef81d..1d21c89b 100644 --- a/tests/base.py +++ b/tests/base.py @@ -25,16 +25,16 @@ class TestMemoryLeaks(unittest.TestCase): iterations = test_iterations - data_dir = os.path.join(os.path.dirname(__file__), "data") + data_dir = os.path.join(os.path.dirname(__file__), 'data') def setUp(self): gc.disable() - self.addTypeEqualityFunc(etype, "assertXmlEqual") + self.addTypeEqualityFunc(etype, 'assertXmlEqual') xmlsec.enable_debug_trace(1) def run(self, result=None): # run first time - super(TestMemoryLeaks, self).run(result=result) + super().run(result=result) if self.iterations == 0: return @@ -43,7 +43,7 @@ def run(self, result=None): m_hits = 0 o_hits = 0 for _ in range(self.iterations): - super(TestMemoryLeaks, self).run(result=result) + super().run(result=result) m_usage_n = resource.getrusage(resource.RUSAGE_SELF).ru_maxrss if m_usage_n > m_usage: m_usage = m_usage_n @@ -58,13 +58,13 @@ def run(self, result=None): if m_hits > int(self.iterations * 0.8): result.buffer = False try: - raise AssertionError("memory leak detected") + raise AssertionError('memory leak detected') except AssertionError: result.addError(self, sys.exc_info()) if o_hits > int(self.iterations * 0.8): result.buffer = False try: - raise AssertionError("unreferenced objects detected") + raise AssertionError('unreferenced objects detected') except AssertionError: result.addError(self, sys.exc_info()) @@ -74,7 +74,7 @@ def path(self, name): def load(self, name): """Load resource by name.""" - with open(self.path(name), "rb") as stream: + with open(self.path(name), 'rb') as stream: return stream.read() def load_xml(self, name, xpath=None): @@ -88,28 +88,26 @@ def load_xml(self, name, xpath=None): def dump(self, root): print(etree.tostring(root)) - def assertXmlEqual(self, first, second, msg=None): # noqa: N802 + def assertXmlEqual(self, first, second, msg=None): """Check equality of etree.roots.""" msg = msg or '' if first.tag != second.tag: - self.fail('Tags do not match: {} and {}. {}'.format(first.tag, second.tag, msg)) + self.fail(f'Tags do not match: {first.tag} and {second.tag}. {msg}') for name, value in first.attrib.items(): if second.attrib.get(name) != value: - self.fail('Attributes do not match: {}={!r}, {}={!r}. {}'.format(name, value, name, second.attrib.get(name), msg)) - for name in second.attrib.keys(): + self.fail(f'Attributes do not match: {name}={value!r}, {name}={second.attrib.get(name)!r}. {msg}') + for name in second.attrib: if name not in first.attrib: - self.fail('x2 has an attribute x1 is missing: {}. {}'.format(name, msg)) + self.fail(f'x2 has an attribute x1 is missing: {name}. {msg}') if not _xml_text_compare(first.text, second.text): - self.fail('text: {!r} != {!r}. {}'.format(first.text, second.text, msg)) + self.fail(f'text: {first.text!r} != {second.text!r}. {msg}') if not _xml_text_compare(first.tail, second.tail): - self.fail('tail: {!r} != {!r}. {}'.format(first.tail, second.tail, msg)) + self.fail(f'tail: {first.tail!r} != {second.tail!r}. {msg}') cl1 = sorted(first.getchildren(), key=lambda x: x.tag) cl2 = sorted(second.getchildren(), key=lambda x: x.tag) if len(cl1) != len(cl2): - self.fail('children length differs, {} != {}. {}'.format(len(cl1), len(cl2), msg)) - i = 0 + self.fail(f'children length differs, {len(cl1)} != {len(cl2)}. {msg}') for c1, c2 in zip(cl1, cl2): - i += 1 self.assertXmlEqual(c1, c2) diff --git a/tests/conftest.py b/tests/conftest.py index 675258c5..a65235d5 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -1,6 +1,5 @@ def pytest_collection_modifyitems(items): - """ - Put the module init test first. + """Put the module init test first. This way, we implicitly check whether any subsequent test fails because of module reinitialization. """ diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index 247f1b18..3f5076d2 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -24,7 +24,7 @@ def find_alts(component_name, alts) -> str: for a in alts: if os.path.exists(a): return a - raise unittest.SkipTest('Required component is missing: {}'.format(component_name)) + raise unittest.SkipTest(f'Required component is missing: {component_name}') def run_cmd(args, softhsm_conf=None): @@ -101,7 +101,7 @@ def run_cmd(args, softhsm_conf=None): def _temp_file() -> str: - f = tempfile.NamedTemporaryFile(delete=False) + f = tempfile.NamedTemporaryFile(delete=False) # noqa: SIM115 p11_test_files.append(f.name) return f.name @@ -123,24 +123,20 @@ def setup() -> None: if softhsm_version == 2: softhsm_db = _temp_dir() f.write( - """ + f""" # Generated by test -directories.tokendir = {} +directories.tokendir = {softhsm_db} objectstore.backend = file log.level = DEBUG -""".format( - softhsm_db - ) +""" ) else: softhsm_db = _temp_file() f.write( - """ + f""" # Generated by test -0:{} -""".format( - softhsm_db - ) +0:{softhsm_db} +""" ) logging.debug('Initializing the token') @@ -227,13 +223,13 @@ def setup() -> None: '[pkcs11_section]', 'engine_id = pkcs11', # dynamic_path, - "MODULE_PATH = {}".format(component_path['P11_MODULE']), + 'MODULE_PATH = {}'.format(component_path['P11_MODULE']), 'init = 0', ] ) ) - with open(openssl_conf, 'r') as f: + with open(openssl_conf) as f: logging.debug('-------- START DEBUG openssl_conf --------') logging.debug(f.readlines()) logging.debug('-------- END DEBUG openssl_conf --------') @@ -309,7 +305,7 @@ def setup() -> None: softhsm_conf=softhsm_conf, ) - # TODO: Should be teardowned in teardown # noqa: T101 + # TODO: Should be teardowned in teardown os.environ['SOFTHSM_CONF'] = softhsm_conf os.environ['SOFTHSM2_CONF'] = softhsm_conf diff --git a/tests/test_constants.py b/tests/test_constants.py index f79d19f0..2c39d5f6 100644 --- a/tests/test_constants.py +++ b/tests/test_constants.py @@ -21,22 +21,22 @@ def _constants(typename): @pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr) def test_transform_str(transform): """Test string representation of ``xmlsec.constants.__Transform``.""" - assert str(transform) == '{}, {}'.format(transform.name, transform.href) + assert str(transform) == f'{transform.name}, {transform.href}' @pytest.mark.parametrize('transform', _constants('__Transform'), ids=repr) def test_transform_repr(transform): """Test raw string representation of ``xmlsec.constants.__Transform``.""" - assert repr(transform) == '__Transform({!r}, {!r}, {})'.format(transform.name, transform.href, transform.usage) + assert repr(transform) == f'__Transform({transform.name!r}, {transform.href!r}, {transform.usage})' @pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr) def test_keydata_str(keydata): """Test string representation of ``xmlsec.constants.__KeyData``.""" - assert str(keydata) == '{}, {}'.format(keydata.name, keydata.href) + assert str(keydata) == f'{keydata.name}, {keydata.href}' @pytest.mark.parametrize('keydata', _constants('__KeyData'), ids=repr) def test_keydata_repr(keydata): """Test raw string representation of ``xmlsec.constants.__KeyData``.""" - assert repr(keydata) == '__KeyData({!r}, {!r})'.format(keydata.name, keydata.href) + assert repr(keydata) == f'__KeyData({keydata.name!r}, {keydata.href!r})' diff --git a/tests/test_doc_examples.py b/tests/test_doc_examples.py index 2fc490f3..7aa8e517 100644 --- a/tests/test_doc_examples.py +++ b/tests/test_doc_examples.py @@ -3,24 +3,17 @@ import contextlib import os import runpy -import sys +from pathlib import Path import pytest -if sys.version_info >= (3, 4): - from pathlib import Path -else: # python2.7 compat - from _pytest.pathlib import Path - - examples_dir = Path(__file__, '../../doc/source/examples').resolve() examples = sorted(examples_dir.glob('*.py')) @contextlib.contextmanager def cd(where_to): - """ - Temporarily change the working directory. + """Temporarily change the working directory. Restore the current working dir after exiting the context. """ @@ -34,8 +27,7 @@ def cd(where_to): @pytest.mark.parametrize('example', examples, ids=lambda p: p.name) def test_doc_example(example): - """ - Verify example scripts included in the docs are up to date. + """Verify example scripts included in the docs are up to date. Execute each script in :file:`docs/source/examples`, not raising any errors is good enough. diff --git a/tests/test_ds.py b/tests/test_ds.py index 38f0b25c..dd0657d3 100644 --- a/tests/test_ds.py +++ b/tests/test_ds.py @@ -25,13 +25,13 @@ def test_no_key(self): def test_del_key(self): ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) del ctx.key self.assertIsNone(ctx.key) def test_set_key(self): ctx = xmlsec.SignatureContext(manager=xmlsec.KeysManager()) - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) def test_set_key_bad_type(self): @@ -46,9 +46,9 @@ def test_set_invalid_key(self): def test_register_id(self): ctx = xmlsec.SignatureContext() - root = self.load_xml("sign_template.xml") - sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id") - ctx.register_id(sign, "Id") + root = self.load_xml('sign_template.xml') + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, 'Id') + ctx.register_id(sign, 'Id') def test_register_id_bad_args(self): ctx = xmlsec.SignatureContext() @@ -57,41 +57,41 @@ def test_register_id_bad_args(self): def test_register_id_with_namespace_without_attribute(self): ctx = xmlsec.SignatureContext() - root = self.load_xml("sign_template.xml") - sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, "Id") + root = self.load_xml('sign_template.xml') + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, 'Id') with self.assertRaisesRegex(xmlsec.Error, 'missing attribute.'): - ctx.register_id(sign, "Id", id_ns='foo') + ctx.register_id(sign, 'Id', id_ns='foo') def test_sign_bad_args(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaises(TypeError): ctx.sign('') def test_sign_fail(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaisesRegex(xmlsec.Error, 'failed to sign'): ctx.sign(self.load_xml('sign1-in.xml')) def test_sign_case1(self): """Should sign a pre-constructed template file using a key from a PEM file.""" - root = self.load_xml("sign1-in.xml") + root = self.load_xml('sign1-in.xml') sign = xmlsec.tree.find_node(root, consts.NodeSignature) self.assertIsNotNone(sign) ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign1-out.xml"), root) + self.assertEqual(self.load_xml('sign1-out.xml'), root) def test_sign_case2(self): """Should sign a dynamicaly constructed template file using a key from a PEM file.""" - root = self.load_xml("sign2-in.xml") + root = self.load_xml('sign2-in.xml') sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) self.assertIsNotNone(sign) root.append(sign) @@ -101,17 +101,17 @@ def test_sign_case2(self): xmlsec.template.add_key_name(ki) ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign2-out.xml"), root) + self.assertEqual(self.load_xml('sign2-out.xml'), root) def test_sign_case3(self): """Should sign a file using a dynamicaly created template, key from PEM and an X509 cert.""" - root = self.load_xml("sign3-in.xml") + root = self.load_xml('sign3-in.xml') sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) self.assertIsNotNone(sign) root.append(sign) @@ -121,23 +121,23 @@ def test_sign_case3(self): xmlsec.template.add_x509_data(ki) ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign3-out.xml"), root) + self.assertEqual(self.load_xml('sign3-out.xml'), root) def test_sign_case4(self): """Should sign a file using a dynamically created template, key from PEM and an X509 cert with custom ns.""" - root = self.load_xml("sign4-in.xml") - xmlsec.tree.add_ids(root, ["ID"]) + root = self.load_xml('sign4-in.xml') + xmlsec.tree.add_ids(root, ['ID']) elem_id = root.get('ID', None) if elem_id: elem_id = '#' + elem_id - sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, ns="ds") + sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1, ns='ds') self.assertIsNotNone(sign) root.append(sign) ref = xmlsec.template.add_reference(sign, consts.TransformSha1, uri=elem_id) @@ -147,18 +147,18 @@ def test_sign_case4(self): xmlsec.template.add_x509_data(ki) ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign4-out.xml"), root) + self.assertEqual(self.load_xml('sign4-out.xml'), root) def test_sign_case5(self): """Should sign a file using a dynamicaly created template, key from PEM file and an X509 certificate.""" - root = self.load_xml("sign5-in.xml") + root = self.load_xml('sign5-in.xml') sign = xmlsec.template.create(root, consts.TransformExclC14N, consts.TransformRsaSha1) self.assertIsNotNone(sign) root.append(sign) @@ -175,11 +175,11 @@ def test_sign_case5(self): xmlsec.template.x509_issuer_serial_add_serial_number(x509_issuer_serial, '1') ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.load_cert_from_file(self.path('rsacert.pem'), consts.KeyDataFormatPem) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) if (1, 2, 36) <= xmlsec.get_libxmlsec_version() <= (1, 2, 37): @@ -190,7 +190,7 @@ def test_sign_case5(self): def test_sign_binary_bad_args(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaises(TypeError): ctx.sign_binary(bytes=1, transform='') @@ -202,23 +202,23 @@ def test_sign_binary_no_key(self): @unittest.skipIf(not hasattr(consts, 'TransformXslt'), reason='XSLT transformations not enabled') def test_sign_binary_invalid_signature_method(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaisesRegex(xmlsec.Error, 'incompatible signature method'): ctx.sign_binary(bytes=b'', transform=consts.TransformXslt) def test_sign_binary(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) - sign = ctx.sign_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1) - self.assertEqual(self.load("sign6-out.bin"), sign) + sign = ctx.sign_binary(self.load('sign6-in.bin'), consts.TransformRsaSha1) + self.assertEqual(self.load('sign6-out.bin'), sign) def test_sign_binary_twice_not_possible(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) data = self.load('sign6-in.bin') ctx.sign_binary(data, consts.TransformRsaSha1) with self.assertRaisesRegex(xmlsec.Error, 'Signature context already used; it is designed for one use only.'): @@ -226,13 +226,13 @@ def test_sign_binary_twice_not_possible(self): def test_verify_bad_args(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaises(TypeError): ctx.verify('') def test_verify_fail(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) with self.assertRaisesRegex(xmlsec.Error, 'failed to verify'): ctx.verify(self.load_xml('sign1-in.xml')) @@ -252,41 +252,41 @@ def test_verify_case_5(self): self.check_verify(5) def check_verify(self, i): - root = self.load_xml("sign{}-out.xml".format(i)) - xmlsec.tree.add_ids(root, ["ID"]) + root = self.load_xml(f'sign{i}-out.xml') + xmlsec.tree.add_ids(root, ['ID']) sign = xmlsec.tree.find_node(root, consts.NodeSignature) self.assertIsNotNone(sign) - self.assertEqual(consts.NodeSignature, sign.tag.partition("}")[2]) + self.assertEqual(consts.NodeSignature, sign.tag.partition('}')[2]) ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsapub.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsapub.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsapub.pem' - self.assertEqual("rsapub.pem", ctx.key.name) + self.assertEqual('rsapub.pem', ctx.key.name) ctx.verify(sign) def test_validate_binary_sign(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) - ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, self.load("sign6-out.bin")) + ctx.verify_binary(self.load('sign6-in.bin'), consts.TransformRsaSha1, self.load('sign6-out.bin')) def test_validate_binary_sign_fail(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) with self.assertRaises(xmlsec.Error): - ctx.verify_binary(self.load("sign6-in.bin"), consts.TransformRsaSha1, b"invalid") + ctx.verify_binary(self.load('sign6-in.bin'), consts.TransformRsaSha1, b'invalid') def test_enable_reference_transform(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) ctx.enable_reference_transform(consts.TransformRsaSha1) def test_enable_reference_transform_bad_args(self): @@ -301,7 +301,7 @@ def test_enable_reference_transform_bad_args(self): def test_enable_signature_transform(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) ctx.enable_signature_transform(consts.TransformRsaSha1) def test_enable_signature_transform_bad_args(self): @@ -316,12 +316,12 @@ def test_enable_signature_transform_bad_args(self): def test_set_enabled_key_data(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) ctx.set_enabled_key_data([consts.KeyDataAes]) def test_set_enabled_key_data_empty(self): ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) ctx.set_enabled_key_data([]) def test_set_enabled_key_data_bad_args(self): diff --git a/tests/test_enc.py b/tests/test_enc.py index 1788b4d6..41f78d74 100644 --- a/tests/test_enc.py +++ b/tests/test_enc.py @@ -28,18 +28,18 @@ def test_no_key(self): def test_get_key(self): ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) self.assertIsNone(ctx.key) - ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + ctx.key = xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem) self.assertIsNotNone(ctx.key) def test_del_key(self): ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) - ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + ctx.key = xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem) del ctx.key self.assertIsNone(ctx.key) def test_set_key(self): ctx = xmlsec.EncryptionContext(manager=xmlsec.KeysManager()) - ctx.key = xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem) + ctx.key = xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem) self.assertIsNotNone(ctx.key) def test_set_key_bad_type(self): @@ -54,16 +54,16 @@ def test_set_invalid_key(self): def test_encrypt_xml(self): root = self.load_xml('enc1-in.xml') - enc_data = xmlsec.template.encrypted_data_create(root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns="xenc") + enc_data = xmlsec.template.encrypted_data_create(root, consts.TransformAes128Cbc, type=consts.TypeEncElement, ns='xenc') xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) xmlsec.template.encrypted_data_ensure_cipher_value(ek) data = root.find('./Data') self.assertIsNotNone(data) manager = xmlsec.KeysManager() - manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + manager.add_key(xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem)) ctx = xmlsec.EncryptionContext(manager) ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) @@ -73,12 +73,12 @@ def test_encrypt_xml(self): enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#aes128-cbc', enc_method.get('Algorithm')) ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) self.assertIsNotNone(ki) enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method2) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', enc_method2.get('Algorithm')) cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) self.assertIsNotNone(cipher_value) @@ -109,32 +109,32 @@ def test_encrypt_xml_fail(self): def test_encrypt_binary(self): root = self.load_xml('enc2-in.xml') enc_data = xmlsec.template.encrypted_data_create( - root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream" + root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns='xenc', mime_type='binary/octet-stream' ) xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) xmlsec.template.encrypted_data_ensure_cipher_value(ek) manager = xmlsec.KeysManager() - manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + manager.add_key(xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem)) ctx = xmlsec.EncryptionContext(manager) ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) encrypted = ctx.encrypt_binary(enc_data, b'test') self.assertIsNotNone(encrypted) - self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + self.assertEqual(f'{{{consts.EncNs}}}{consts.NodeEncryptedData}', encrypted.tag) enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#aes128-cbc', enc_method.get('Algorithm')) ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) self.assertIsNotNone(ki) enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method2) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', enc_method2.get('Algorithm')) cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) self.assertIsNotNone(cipher_value) @@ -151,15 +151,15 @@ def test_encrypt_binary_bad_template(self): def test_encrypt_uri(self): root = self.load_xml('enc2-in.xml') enc_data = xmlsec.template.encrypted_data_create( - root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns="xenc", mime_type="binary/octet-stream" + root, consts.TransformAes128Cbc, type=consts.TypeEncContent, ns='xenc', mime_type='binary/octet-stream' ) xmlsec.template.encrypted_data_ensure_cipher_value(enc_data) - ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns="dsig") + ki = xmlsec.template.encrypted_data_ensure_key_info(enc_data, ns='dsig') ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) xmlsec.template.encrypted_data_ensure_cipher_value(ek) manager = xmlsec.KeysManager() - manager.add_key(xmlsec.Key.from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatCertPem)) + manager.add_key(xmlsec.Key.from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatCertPem)) ctx = xmlsec.EncryptionContext(manager) ctx.key = xmlsec.Key.generate(consts.KeyDataAes, 128, consts.KeyDataTypeSession) @@ -169,17 +169,17 @@ def test_encrypt_uri(self): encrypted = ctx.encrypt_binary(enc_data, 'file://' + tmpfile.name) self.assertIsNotNone(encrypted) - self.assertEqual("{{{}}}{}".format(consts.EncNs, consts.NodeEncryptedData), encrypted.tag) + self.assertEqual(f'{{{consts.EncNs}}}{consts.NodeEncryptedData}', encrypted.tag) enc_method = xmlsec.tree.find_child(enc_data, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#aes128-cbc", enc_method.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#aes128-cbc', enc_method.get('Algorithm')) ki = xmlsec.tree.find_child(enc_data, consts.NodeKeyInfo, consts.DSigNs) self.assertIsNotNone(ki) enc_method2 = xmlsec.tree.find_node(ki, consts.NodeEncryptionMethod, consts.EncNs) self.assertIsNotNone(enc_method2) - self.assertEqual("http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p", enc_method2.get("Algorithm")) + self.assertEqual('http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p', enc_method2.get('Algorithm')) cipher_value = xmlsec.tree.find_node(ki, consts.NodeCipherValue, consts.EncNs) self.assertIsNotNone(cipher_value) @@ -205,7 +205,7 @@ def test_decrypt_key(self): self.assertIsNotNone(enc_key) manager = xmlsec.KeysManager() - manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + manager.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) ctx = xmlsec.EncryptionContext(manager) keydata = ctx.decrypt(enc_key) ctx.reset() @@ -215,19 +215,19 @@ def test_decrypt_key(self): self.assertIsNotNone(enc_data) decrypted = ctx.decrypt(enc_data) self.assertIsNotNone(decrypted) - self.assertEqual(self.load_xml("enc3-in.xml"), decrypted) + self.assertEqual(self.load_xml('enc3-in.xml'), decrypted) def check_decrypt(self, i): - root = self.load_xml('enc{}-out.xml'.format(i)) + root = self.load_xml(f'enc{i}-out.xml') enc_data = xmlsec.tree.find_child(root, consts.NodeEncryptedData, consts.EncNs) self.assertIsNotNone(enc_data) manager = xmlsec.KeysManager() - manager.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + manager.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) ctx = xmlsec.EncryptionContext(manager) decrypted = ctx.decrypt(enc_data) self.assertIsNotNone(decrypted) - self.assertEqual(self.load_xml("enc{}-in.xml".format(i)), root) + self.assertEqual(self.load_xml(f'enc{i}-in.xml'), root) def test_decrypt_bad_args(self): ctx = xmlsec.EncryptionContext() diff --git a/tests/test_keys.py b/tests/test_keys.py index 0d41abef..977ddf82 100644 --- a/tests/test_keys.py +++ b/tests/test_keys.py @@ -9,33 +9,32 @@ class TestKeys(base.TestMemoryLeaks): def test_key_from_memory(self): - key = xmlsec.Key.from_memory(self.load("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_memory(self.load('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) def test_key_from_memory_with_bad_args(self): with self.assertRaises(TypeError): - xmlsec.Key.from_memory(1, format="") + xmlsec.Key.from_memory(1, format='') def test_key_from_memory_invalid_data(self): with self.assertRaisesRegex(xmlsec.Error, '.*cannot load key.*'): xmlsec.Key.from_memory(b'foo', format=consts.KeyDataFormatPem) def test_key_from_file(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) def test_key_from_file_with_bad_args(self): with self.assertRaises(TypeError): - xmlsec.Key.from_file(1, format="") + xmlsec.Key.from_file(1, format='') def test_key_from_invalid_file(self): - with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): - with tempfile.NamedTemporaryFile() as tmpfile: - tmpfile.write(b'foo') - xmlsec.Key.from_file(tmpfile.name, format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'), tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + xmlsec.Key.from_file(tmpfile.name, format=consts.KeyDataFormatPem) def test_key_from_fileobj(self): - with open(self.path("rsakey.pem"), "rb") as fobj: + with open(self.path('rsakey.pem'), 'rb') as fobj: key = xmlsec.Key.from_file(fobj, format=consts.KeyDataFormatPem) self.assertIsNotNone(key) @@ -51,71 +50,69 @@ def test_generate(self): def test_generate_with_bad_args(self): with self.assertRaises(TypeError): - xmlsec.Key.generate(klass="", size="", type="") + xmlsec.Key.generate(klass='', size='', type='') def test_generate_invalid_size(self): with self.assertRaisesRegex(xmlsec.Error, '.*cannot generate key.*'): xmlsec.Key.generate(klass=consts.KeyDataAes, size=0, type=consts.KeyDataTypeSession) def test_from_binary_file(self): - key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path("deskey.bin")) + key = xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=self.path('deskey.bin')) self.assertIsNotNone(key) def test_from_binary_file_with_bad_args(self): with self.assertRaises(TypeError): - xmlsec.Key.from_binary_file(klass="", filename=1) + xmlsec.Key.from_binary_file(klass='', filename=1) def test_from_invalid_binary_file(self): - with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): - with tempfile.NamedTemporaryFile() as tmpfile: - tmpfile.write(b'foo') - xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=tmpfile.name) + with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'), tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + xmlsec.Key.from_binary_file(klass=consts.KeyDataDes, filename=tmpfile.name) def test_from_binary_data(self): - key = xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=self.load("deskey.bin")) + key = xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=self.load('deskey.bin')) self.assertIsNotNone(key) def test_from_binary_data_with_bad_args(self): with self.assertRaises(TypeError): - xmlsec.Key.from_binary_data(klass="", data=1) + xmlsec.Key.from_binary_data(klass='', data=1) def test_from_invalid_binary_data(self): with self.assertRaisesRegex(xmlsec.Error, '.*cannot read key.*'): xmlsec.Key.from_binary_data(klass=consts.KeyDataDes, data=b'') def test_load_cert_from_file(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - key.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem) + key.load_cert_from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatPem) def test_load_cert_from_file_with_bad_args(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) with self.assertRaises(TypeError): - key.load_cert_from_file(1, format="") + key.load_cert_from_file(1, format='') def test_load_cert_from_invalid_file(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): - with tempfile.NamedTemporaryFile() as tmpfile: - tmpfile.write(b'foo') - key.load_cert_from_file(tmpfile.name, format=consts.KeyDataFormatPem) + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'), tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + key.load_cert_from_file(tmpfile.name, format=consts.KeyDataFormatPem) def test_load_cert_from_fileobj(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - with open(self.path("rsacert.pem"), "rb") as fobj: + with open(self.path('rsacert.pem'), 'rb') as fobj: key.load_cert_from_file(fobj, format=consts.KeyDataFormatPem) def test_load_cert_from_fileobj_with_bad_args(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - with self.assertRaises(TypeError), open(self.path("rsacert.pem"), "rb") as fobj: + with self.assertRaises(TypeError), open(self.path('rsacert.pem'), 'rb') as fobj: key.load_cert_from_file(fobj, format='') def test_load_cert_from_invalid_fileobj(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) with tempfile.NamedTemporaryFile(delete=False) as tmpfile: tmpfile.write(b'foo') @@ -123,41 +120,41 @@ def test_load_cert_from_invalid_fileobj(self): key.load_cert_from_file(fp, format=consts.KeyDataFormatPem) def test_load_cert_from_memory(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) - key.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem) + key.load_cert_from_memory(self.load('rsacert.pem'), format=consts.KeyDataFormatPem) def test_load_cert_from_memory_with_bad_args(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) with self.assertRaises(TypeError): - key.load_cert_from_memory(1, format="") + key.load_cert_from_memory(1, format='') def test_load_cert_from_memory_invalid_data(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNotNone(key) with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): key.load_cert_from_memory(b'', format=consts.KeyDataFormatPem) def test_get_name(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) self.assertIsNone(key.name) def test_get_name_invalid_key(self): key = xmlsec.Key() with self.assertRaisesRegex(ValueError, 'key is not ready'): - key.name + key.name # noqa: B018 def test_del_name(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) - key.name = "rsakey" + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + key.name = 'rsakey' del key.name self.assertIsNone(key.name) def test_set_name(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) - key.name = "rsakey" - self.assertEqual("rsakey", key.name) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) + key.name = 'rsakey' + self.assertEqual('rsakey', key.name) def test_set_name_invalid_key(self): key = xmlsec.Key() @@ -165,56 +162,55 @@ def test_set_name_invalid_key(self): key.name = 'foo' def test_copy(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) key2 = copy.copy(key) del key - key2.load_cert_from_file(self.path("rsacert.pem"), format=consts.KeyDataFormatPem) + key2.load_cert_from_file(self.path('rsacert.pem'), format=consts.KeyDataFormatPem) class TestKeysManager(base.TestMemoryLeaks): def test_add_key(self): - key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) mngr = xmlsec.KeysManager() mngr.add_key(key) def test_add_key_with_bad_args(self): mngr = xmlsec.KeysManager() with self.assertRaises(TypeError): - mngr.add_key("") + mngr.add_key('') def test_load_cert(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) - mngr.load_cert(self.path("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) + mngr.load_cert(self.path('rsacert.pem'), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) def test_load_cert_with_bad_args(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) - with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): - with tempfile.NamedTemporaryFile() as tmpfile: - tmpfile.write(b'foo') - mngr.load_cert(tmpfile.name, format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) + with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'), tempfile.NamedTemporaryFile() as tmpfile: + tmpfile.write(b'foo') + mngr.load_cert(tmpfile.name, format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) def test_load_invalid_cert(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) with self.assertRaises(TypeError): - mngr.load_cert(1, format="", type="") + mngr.load_cert(1, format='', type='') def test_load_cert_from_memory(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) - mngr.load_cert_from_memory(self.load("rsacert.pem"), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) + mngr.load_cert_from_memory(self.load('rsacert.pem'), format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) def test_load_cert_from_memory_with_bad_args(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) with self.assertRaises(TypeError): - mngr.load_cert_from_memory(1, format="", type="") + mngr.load_cert_from_memory(1, format='', type='') def test_load_cert_from_memory_invalid_data(self): mngr = xmlsec.KeysManager() - mngr.add_key(xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem)) + mngr.add_key(xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem)) with self.assertRaisesRegex(xmlsec.Error, '.*cannot load cert.*'): mngr.load_cert_from_memory(b'', format=consts.KeyDataFormatPem, type=consts.KeyDataTypeTrusted) diff --git a/tests/test_main.py b/tests/test_main.py index 3db18582..8f1501f2 100644 --- a/tests/test_main.py +++ b/tests/test_main.py @@ -10,7 +10,7 @@ class TestBase64LineSize(base.TestMemoryLeaks): def tearDown(self): xmlsec.base64_default_line_size(64) - super(TestBase64LineSize, self).tearDown() + super().tearDown() def test_get_base64_default_line_size(self): self.assertEqual(xmlsec.base64_default_line_size(), 64) @@ -43,12 +43,12 @@ def setUp(self): xmlsec.cleanup_callbacks() def _sign_doc(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) - xmlsec.template.add_reference(sign, consts.TransformSha1, uri="cid:123456") + xmlsec.template.add_reference(sign, consts.TransformSha1, uri='cid:123456') ctx = xmlsec.SignatureContext() - ctx.key = xmlsec.Key.from_file(self.path("rsakey.pem"), format=consts.KeyDataFormatPem) + ctx.key = xmlsec.Key.from_file(self.path('rsakey.pem'), format=consts.KeyDataFormatPem) ctx.sign(sign) return sign @@ -78,7 +78,7 @@ def _register_match_callbacks(self): def _find(self, elem, *tags): try: return elem.xpath( - './' + '/'.join('xmldsig:{}'.format(tag) for tag in tags), + './' + '/'.join(f'xmldsig:{tag}' for tag in tags), namespaces={ 'xmldsig': 'http://www.w3.org/2000/09/xmldsig#', }, @@ -125,7 +125,7 @@ def match_cb(filename): self._verify_external_data_signature() self.assertEqual(bad_match_calls, 0) - @skipIf(sys.platform == "win32", "unclear behaviour on windows") + @skipIf(sys.platform == 'win32', 'unclear behaviour on windows') def test_failed_sign_because_default_callbacks(self): mismatch_calls = 0 diff --git a/tests/test_pkcs11.py b/tests/test_pkcs11.py index accd29ae..cba1a3f0 100644 --- a/tests/test_pkcs11.py +++ b/tests/test_pkcs11.py @@ -2,7 +2,7 @@ from tests import base from xmlsec import constants as consts -KEY_URL = "pkcs11;pkcs11:token=test;object=test;pin-value=secret1" +KEY_URL = 'pkcs11;pkcs11:token=test;object=test;pin-value=secret1' def setUpModule(): @@ -43,7 +43,7 @@ def test_sign_fail(self): def test_sign_case1(self): """Should sign a pre-constructed template file using a key from a pkcs11 engine.""" - root = self.load_xml("sign1-in.xml") + root = self.load_xml('sign1-in.xml') sign = xmlsec.tree.find_node(root, consts.NodeSignature) self.assertIsNotNone(sign) @@ -51,7 +51,7 @@ def test_sign_case1(self): ctx.key = xmlsec.Key.from_engine(KEY_URL) self.assertIsNotNone(ctx.key) ctx.key.name = 'rsakey.pem' - self.assertEqual("rsakey.pem", ctx.key.name) + self.assertEqual('rsakey.pem', ctx.key.name) ctx.sign(sign) - self.assertEqual(self.load_xml("sign1-out.xml"), root) + self.assertEqual(self.load_xml('sign1-out.xml'), root) diff --git a/tests/test_templates.py b/tests/test_templates.py index 3bae7e55..bbf7f42d 100644 --- a/tests/test_templates.py +++ b/tests/test_templates.py @@ -10,61 +10,61 @@ class TestTemplates(base.TestMemoryLeaks): def test_create(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create( - root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1, id="Id", ns="test" + root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1, id='Id', ns='test' ) - self.assertEqual("Id", sign.get("Id")) - self.assertEqual("test", sign.prefix) + self.assertEqual('Id', sign.get('Id')) + self.assertEqual('test', sign.prefix) def test_create_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.create('', c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) def test_encrypt_data_create(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') enc = xmlsec.template.encrypted_data_create( - root, method=consts.TransformDes3Cbc, id="Id", type="Type", mime_type="MimeType", encoding="Encoding", ns="test" + root, method=consts.TransformDes3Cbc, id='Id', type='Type', mime_type='MimeType', encoding='Encoding', ns='test' ) - for a in ("Id", "Type", "MimeType", "Encoding"): + for a in ('Id', 'Type', 'MimeType', 'Encoding'): self.assertEqual(a, enc.get(a)) - self.assertEqual("test", enc.prefix) + self.assertEqual('test', enc.prefix) def test_ensure_key_info(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) - ki = xmlsec.template.ensure_key_info(sign, id="Id") - self.assertEqual("Id", ki.get("Id")) + ki = xmlsec.template.ensure_key_info(sign, id='Id') + self.assertEqual('Id', ki.get('Id')) def test_ensure_key_info_fail(self): with self.assertRaisesRegex(xmlsec.Error, 'cannot ensure key info.'): - xmlsec.template.ensure_key_info(etree.fromstring(b''), id="Id") + xmlsec.template.ensure_key_info(etree.fromstring(b''), id='Id') def test_ensure_key_info_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.ensure_key_info('', id=0) def test_add_encrypted_key(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) ek = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep) - self.assertEqual(ek, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeEncryptedKey, consts.EncNs)) - ek2 = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep, id="Id", type="Type", recipient="Recipient") - for a in ("Id", "Type", "Recipient"): + self.assertEqual(ek, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeEncryptedKey, consts.EncNs)) + ek2 = xmlsec.template.add_encrypted_key(ki, consts.TransformRsaOaep, id='Id', type='Type', recipient='Recipient') + for a in ('Id', 'Type', 'Recipient'): self.assertEqual(a, ek2.get(a)) def test_add_key_name(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) kn = xmlsec.template.add_key_name(ki) - self.assertEqual(kn, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyName, consts.DSigNs)) - kn2 = xmlsec.template.add_key_name(ki, name="name") - self.assertEqual("name", kn2.text) + self.assertEqual(kn, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeKeyName, consts.DSigNs)) + kn2 = xmlsec.template.add_key_name(ki, name='name') + self.assertEqual('name', kn2.text) def test_add_key_name_none(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) kn2 = xmlsec.template.add_key_name(ki, name=None) @@ -76,10 +76,10 @@ def test_add_key_name_bad_args(self): xmlsec.template.add_key_name('') def test_add_reference(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) - ref = xmlsec.template.add_reference(sign, consts.TransformSha1, id="Id", uri="URI", type="Type") - for a in ("Id", "URI", "Type"): + ref = xmlsec.template.add_reference(sign, consts.TransformSha1, id='Id', uri='URI', type='Type') + for a in ('Id', 'URI', 'Type'): self.assertEqual(a, ref.get(a)) def test_add_reference_bad_args(self): @@ -99,18 +99,18 @@ def test_add_transform_bad_args(self): xmlsec.template.add_transform(etree.Element('root'), '') def test_add_key_value(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) kv = xmlsec.template.add_key_value(ki) - self.assertEqual(kv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeKeyValue, consts.DSigNs)) + self.assertEqual(kv, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeKeyValue, consts.DSigNs)) def test_add_key_value_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.add_key_value('') def test_add_x509_data(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) x509 = xmlsec.template.add_x509_data(ki) @@ -121,22 +121,22 @@ def test_add_x509_data(self): xmlsec.template.x509_data_add_subject_name(x509) xmlsec.template.x509_issuer_serial_add_issuer_name(issuer) xmlsec.template.x509_issuer_serial_add_serial_number(issuer) - self.assertEqual(x509, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeX509Data, consts.DSigNs)) + self.assertEqual(x509, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeX509Data, consts.DSigNs)) def test_add_x509_data_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.add_x509_data('') def test_x509_issuer_serial_add_issuer(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ki = xmlsec.template.ensure_key_info(sign) x509 = xmlsec.template.add_x509_data(ki) issuer = xmlsec.template.x509_data_add_issuer_serial(x509) - name = xmlsec.template.x509_issuer_serial_add_issuer_name(issuer, name="Name") - serial = xmlsec.template.x509_issuer_serial_add_serial_number(issuer, serial="Serial") - self.assertEqual("Name", name.text) - self.assertEqual("Serial", serial.text) + name = xmlsec.template.x509_issuer_serial_add_issuer_name(issuer, name='Name') + serial = xmlsec.template.x509_issuer_serial_add_serial_number(issuer, serial='Serial') + self.assertEqual('Name', name.text) + self.assertEqual('Serial', serial.text) def test_x509_issuer_serial_add_issuer_bad_args(self): with self.assertRaises(TypeError): @@ -175,23 +175,23 @@ def test_encrypted_data_create_bad_args(self): xmlsec.template.encrypted_data_create('', 0) def test_encrypted_data_ensure_cipher_value(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) cv = xmlsec.template.encrypted_data_ensure_cipher_value(enc) - self.assertEqual(cv, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeCipherValue, consts.EncNs)) + self.assertEqual(cv, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeCipherValue, consts.EncNs)) def test_encrypted_data_ensure_cipher_value_bad_args(self): with self.assertRaises(TypeError): xmlsec.template.encrypted_data_ensure_cipher_value('') def test_encrypted_data_ensure_key_info(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') enc = xmlsec.template.encrypted_data_create(root, method=consts.TransformDes3Cbc) ki = xmlsec.template.encrypted_data_ensure_key_info(enc) - self.assertEqual(ki, xmlsec.tree.find_node(self.load_xml("enc_template.xml"), consts.NodeKeyInfo, consts.DSigNs)) - ki2 = xmlsec.template.encrypted_data_ensure_key_info(enc, id="Id", ns="test") - self.assertEqual("Id", ki2.get("Id")) - self.assertEqual("test", ki2.prefix) + self.assertEqual(ki, xmlsec.tree.find_node(self.load_xml('enc_template.xml'), consts.NodeKeyInfo, consts.DSigNs)) + ki2 = xmlsec.template.encrypted_data_ensure_key_info(enc, id='Id', ns='test') + self.assertEqual('Id', ki2.get('Id')) + self.assertEqual('test', ki2.prefix) def test_encrypted_data_ensure_key_info_bad_args(self): with self.assertRaises(TypeError): @@ -199,14 +199,14 @@ def test_encrypted_data_ensure_key_info_bad_args(self): @unittest.skipIf(not hasattr(consts, 'TransformXslt'), reason='XSLT transformations not enabled') def test_transform_add_c14n_inclusive_namespaces(self): - root = self.load_xml("doc.xml") + root = self.load_xml('doc.xml') sign = xmlsec.template.create(root, c14n_method=consts.TransformExclC14N, sign_method=consts.TransformRsaSha1) ref = xmlsec.template.add_reference(sign, consts.TransformSha1) trans1 = xmlsec.template.add_transform(ref, consts.TransformEnveloped) - xmlsec.template.transform_add_c14n_inclusive_namespaces(trans1, "default") + xmlsec.template.transform_add_c14n_inclusive_namespaces(trans1, 'default') trans2 = xmlsec.template.add_transform(ref, consts.TransformXslt) - xmlsec.template.transform_add_c14n_inclusive_namespaces(trans2, ["ns1", "ns2"]) - self.assertEqual(ref, xmlsec.tree.find_node(self.load_xml("sign_template.xml"), consts.NodeReference, consts.DSigNs)) + xmlsec.template.transform_add_c14n_inclusive_namespaces(trans2, ['ns1', 'ns2']) + self.assertEqual(ref, xmlsec.tree.find_node(self.load_xml('sign_template.xml'), consts.NodeReference, consts.DSigNs)) def test_transform_add_c14n_inclusive_namespaces_bad_args(self): with self.assertRaises(TypeError): diff --git a/tests/test_tree.py b/tests/test_tree.py index 4c79c8de..5e80a60a 100644 --- a/tests/test_tree.py +++ b/tests/test_tree.py @@ -6,7 +6,7 @@ class TestTree(base.TestMemoryLeaks): def test_find_child(self): - root = self.load_xml("sign_template.xml") + root = self.load_xml('sign_template.xml') si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs) self.assertEqual(consts.NodeSignedInfo, si.tag.partition('}')[2]) self.assertIsNone(xmlsec.tree.find_child(root, consts.NodeReference)) @@ -17,7 +17,7 @@ def test_find_child_bad_args(self): xmlsec.tree.find_child('', 0, True) def test_find_parent(self): - root = self.load_xml("sign_template.xml") + root = self.load_xml('sign_template.xml') si = xmlsec.tree.find_child(root, consts.NodeSignedInfo, consts.DSigNs) self.assertIs(root, xmlsec.tree.find_parent(si, consts.NodeSignature)) self.assertIsNone(xmlsec.tree.find_parent(root, consts.NodeSignedInfo)) @@ -27,7 +27,7 @@ def test_find_parent_bad_args(self): xmlsec.tree.find_parent('', 0, True) def test_find_node(self): - root = self.load_xml("sign_template.xml") + root = self.load_xml('sign_template.xml') ref = xmlsec.tree.find_node(root, consts.NodeReference) self.assertEqual(consts.NodeReference, ref.tag.partition('}')[2]) self.assertIsNone(xmlsec.tree.find_node(root, consts.NodeReference, consts.EncNs)) @@ -37,8 +37,8 @@ def test_find_node_bad_args(self): xmlsec.tree.find_node('', 0, True) def test_add_ids(self): - root = self.load_xml("sign_template.xml") - xmlsec.tree.add_ids(root, ["id1", "id2", "id3"]) + root = self.load_xml('sign_template.xml') + xmlsec.tree.add_ids(root, ['id1', 'id2', 'id3']) def test_add_ids_bad_args(self): with self.assertRaises(TypeError): diff --git a/tests/test_type_stubs.py b/tests/test_type_stubs.py index 9ed8f1e2..82f7df7f 100644 --- a/tests/test_type_stubs.py +++ b/tests/test_type_stubs.py @@ -40,8 +40,7 @@ class __TransformNoHref(NamedTuple): # __Transform type def gen_constants_stub(): - """ - Generate contents of the file:`xmlsec/constants.pyi`. + """Generate contents of the file:`xmlsec/constants.pyi`. Simply load all constants at runtime, generate appropriate type hint for each constant type. @@ -53,7 +52,7 @@ def process_constant(name): type_name = type(obj).__name__ if type_name in ('__KeyData', '__Transform') and obj.href is None: type_name += 'NoHref' - return '{name}: Final[{type_name}]'.format(name=name, type_name=type_name) + return f'{name}: Final[{type_name}]' names = list(sorted(name for name in dir(xmlsec.constants) if not name.startswith('__'))) lines = [process_constant(name) for name in names] @@ -61,8 +60,7 @@ def process_constant(name): def test_xmlsec_constants_stub(request): - """ - Generate the stub file for :mod:`xmlsec.constants` from existing code. + """Generate the stub file for :mod:`xmlsec.constants` from existing code. Compare it against the existing stub :file:`xmlsec/constants.pyi`. """ diff --git a/tests/test_xmlsec.py b/tests/test_xmlsec.py index 303d7f8f..52dce2b3 100644 --- a/tests/test_xmlsec.py +++ b/tests/test_xmlsec.py @@ -4,8 +4,7 @@ class TestModule(base.TestMemoryLeaks): def test_reinitialize_module(self): - """ - This test doesn't explicitly verify anything, but will be invoked first in the suite. + """This test doesn't explicitly verify anything, but will be invoked first in the suite. So if the subsequent tests don't fail, we know that the ``init()``/``shutdown()`` function pair doesn't break anything. From a89f8043c1b54e82b0ae38fcbfa237a6358e0dac Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 21 Jul 2025 21:19:19 +0200 Subject: [PATCH 352/378] [pre-commit.ci] pre-commit autoupdate (#360) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.3 → v0.12.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.3...v0.12.4) - [github.com/pre-commit/mirrors-mypy: v1.16.1 → v1.17.0](https://github.com/pre-commit/mirrors-mypy/compare/v1.16.1...v1.17.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 48abcc6f..315bd1ad 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.3 + rev: v0.12.4 hooks: - id: ruff args: ["--fix"] @@ -28,7 +28,7 @@ repos: args: [--autofix] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.16.1 + rev: v1.17.0 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From b2e4bd6be9b509a5f656a544199e8ca88b65106b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 31 Jul 2025 15:07:58 +0200 Subject: [PATCH 353/378] [pre-commit.ci] pre-commit autoupdate (#363) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.4 → v0.12.5](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.4...v0.12.5) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 315bd1ad..0f038b24 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.4 + rev: v0.12.5 hooks: - id: ruff args: ["--fix"] From adb329ee06b08f270209687650531f70a121ff1f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 4 Aug 2025 22:34:47 +0200 Subject: [PATCH 354/378] [pre-commit.ci] pre-commit autoupdate (#365) --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0f038b24..0e6d0afc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.5 + rev: v0.12.7 hooks: - id: ruff args: ["--fix"] @@ -28,7 +28,7 @@ repos: args: [--autofix] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.17.0 + rev: v1.17.1 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From b70c0db61988c70c196dbc6bd719be4b92a2b4d1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 12 Aug 2025 10:15:09 +0200 Subject: [PATCH 355/378] [pre-commit.ci] pre-commit autoupdate (#370) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.7 → v0.12.8](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.7...v0.12.8) - [github.com/pre-commit/pre-commit-hooks: v5.0.0 → v6.0.0](https://github.com/pre-commit/pre-commit-hooks/compare/v5.0.0...v6.0.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 0e6d0afc..14395966 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.7 + rev: v0.12.8 hooks: - id: ruff args: ["--fix"] @@ -11,7 +11,7 @@ repos: types: [python] - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v5.0.0 + rev: v6.0.0 hooks: - id: no-commit-to-branch - id: trailing-whitespace From 511d97b4fe99d81ab9cfdeff8405f1413d2f755c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 19 Aug 2025 15:34:56 +0200 Subject: [PATCH 356/378] [pre-commit.ci] pre-commit autoupdate (#372) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.8 → v0.12.9](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.8...v0.12.9) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 14395966..ca70eb16 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.8 + rev: v0.12.9 hooks: - id: ruff args: ["--fix"] From d7cc117147711eb33464cf35eddce1b4bb65cc4d Mon Sep 17 00:00:00 2001 From: Paul Zakin Date: Wed, 20 Aug 2025 04:25:25 -0400 Subject: [PATCH 357/378] Update Alpine linux installation document (#373) --- README.md | 2 +- doc/source/install.rst | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 6abd6a5a..60bde880 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,7 @@ port install libxml2 xmlsec pkgconfig ### Alpine ``` bash -apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec +apk add build-base openssl libffi-dev openssl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec ``` ## Troubleshooting diff --git a/doc/source/install.rst b/doc/source/install.rst index 834b9acb..c892a3ea 100644 --- a/doc/source/install.rst +++ b/doc/source/install.rst @@ -59,7 +59,7 @@ Alpine .. code-block:: bash - apk add build-base libressl libffi-dev libressl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec + apk add build-base openssl libffi-dev openssl-dev libxslt-dev libxml2-dev xmlsec-dev xmlsec Troubleshooting From 71ad25b101556de2824f98b9a63350a7c7568c88 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 1 Sep 2025 11:07:18 +0200 Subject: [PATCH 358/378] [pre-commit.ci] pre-commit autoupdate (#374) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.9 → v0.12.10](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.9...v0.12.10) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index ca70eb16..deef08b2 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.9 + rev: v0.12.10 hooks: - id: ruff args: ["--fix"] From 5f82f6b4e7b9468ebc4fb7225fc6dcbaadcb3dce Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 1 Sep 2025 14:28:51 +0200 Subject: [PATCH 359/378] Bump libxml2 version to 2.14.5 for building wheels (#375) The goal is to keep it sync with lxml builds which in version 6.0.1 is using libxml2-2.14.5. --- .github/workflows/wheels.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 62d48b4b..f29019f0 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -110,7 +110,7 @@ jobs: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} env: - PYXMLSEC_LIBXML2_VERSION: 2.14.4 + PYXMLSEC_LIBXML2_VERSION: 2.14.5 PYXMLSEC_LIBXSLT_VERSION: 1.1.43 steps: From 3933936ece71dc82bfdfa4ab35d80869e7af2f57 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 2 Sep 2025 14:39:28 +0200 Subject: [PATCH 360/378] [pre-commit.ci] pre-commit autoupdate (#376) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.10 → v0.12.11](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.10...v0.12.11) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index deef08b2..46ee7c85 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.10 + rev: v0.12.11 hooks: - id: ruff args: ["--fix"] From 699aa1e63c883adaa54c2e795446c529ec516ca7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 9 Sep 2025 13:56:47 +0200 Subject: [PATCH 361/378] [pre-commit.ci] pre-commit autoupdate (#377) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.11 → v0.12.12](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.11...v0.12.12) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 46ee7c85..11bf9cc6 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.11 + rev: v0.12.12 hooks: - id: ruff args: ["--fix"] From 5216e038615fc02466a51427a7f9f132e96bd884 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 12 Sep 2025 09:29:54 +0200 Subject: [PATCH 362/378] Add missing typing for id and ns parameters of template.create function (#378) --- src/xmlsec/template.pyi | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/xmlsec/template.pyi b/src/xmlsec/template.pyi index a5199fc8..d1755fa2 100644 --- a/src/xmlsec/template.pyi +++ b/src/xmlsec/template.pyi @@ -15,7 +15,7 @@ def add_reference( ) -> _Element: ... def add_transform(node: _Element, transform: Transform) -> Any: ... def add_x509_data(node: _Element) -> _Element: ... -def create(node: _Element, c14n_method: Transform, sign_method: Transform) -> _Element: ... +def create(node: _Element, c14n_method: Transform, sign_method: Transform, id: str | None = ..., ns: str | None = ...) -> _Element: ... def encrypted_data_create( node: _Element, method: Transform, From 869e853d2396e1456bfc079d321ad38adadc71cd Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Wed, 17 Sep 2025 08:31:09 +0200 Subject: [PATCH 363/378] [pre-commit.ci] pre-commit autoupdate (#379) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.12.12 → v0.13.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.12.12...v0.13.0) - [github.com/pre-commit/mirrors-mypy: v1.17.1 → v1.18.1](https://github.com/pre-commit/mirrors-mypy/compare/v1.17.1...v1.18.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 11bf9cc6..6403b4cc 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.12.12 + rev: v0.13.0 hooks: - id: ruff args: ["--fix"] @@ -28,7 +28,7 @@ repos: args: [--autofix] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.17.1 + rev: v1.18.1 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From 2075d146e849847257893958eb5a30cd1943f0b1 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 22 Sep 2025 21:09:30 +0200 Subject: [PATCH 364/378] Lock libxml2 to v2.14.6 in manylinux workflow (#380) It seems that xmlsec library build fails with libxml2 v2.15.0. Let's lock it for now until the issue is resolved in the main repository. --- .github/workflows/manylinux.yml | 1 + tests/softhsm_setup.py | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 357e93eb..550a8b34 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -32,6 +32,7 @@ jobs: - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true + PYXMLSEC_LIBXML2_VERSION: 2.14.6 # Lock it to libxml2 2.14.6 until the issue with 2.15.x is resolved; e.g. https://github.com/lsh123/xmlsec/issues/948 GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | /opt/python/${{ matrix.python-abi }}/bin/python -m build diff --git a/tests/softhsm_setup.py b/tests/softhsm_setup.py index 3f5076d2..d55c16fd 100644 --- a/tests/softhsm_setup.py +++ b/tests/softhsm_setup.py @@ -140,7 +140,7 @@ def setup() -> None: ) logging.debug('Initializing the token') - out, err = run_cmd( + _, _ = run_cmd( [ component_path['SOFTHSM'], '--slot', From 6786271f4b1d580194dd6f6121e0f4f0fbb5c3df Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 21:09:50 +0200 Subject: [PATCH 365/378] [pre-commit.ci] pre-commit autoupdate (#381) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.13.0 → v0.13.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.0...v0.13.1) - [github.com/pre-commit/mirrors-mypy: v1.18.1 → v1.18.2](https://github.com/pre-commit/mirrors-mypy/compare/v1.18.1...v1.18.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 6403b4cc..5e38393e 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.0 + rev: v0.13.1 hooks: - id: ruff args: ["--fix"] @@ -28,7 +28,7 @@ repos: args: [--autofix] - repo: https://github.com/pre-commit/mirrors-mypy - rev: v1.18.1 + rev: v1.18.2 hooks: - id: mypy exclude: (setup.py|tests/.*.py|doc/.*) From e24a84c1503e5ca250f163a71bc366551d370604 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 30 Sep 2025 11:16:38 +0200 Subject: [PATCH 366/378] [pre-commit.ci] pre-commit autoupdate (#382) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.13.1 → v0.13.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.1...v0.13.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 5e38393e..2a20f7cb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.1 + rev: v0.13.2 hooks: - id: ruff args: ["--fix"] From 11beda8c3fddf680c8d0e315bb20cbf4d2edfd0e Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 6 Oct 2025 21:13:49 +0200 Subject: [PATCH 367/378] Replace urlretrieve with streaming download using urlopen (#384) Updated setup.py to replace urllib.request.urlretrieve with a streaming download helper based on urlopen. This avoids the drawbacks of urlretrieve, such as lack of streaming support and limited control over requests. Using urlopen allows downloads to be written in chunks, reduces memory usage, and makes it easier to extend the logic with custom headers, retries, or checksum verification in the future. This improves the reliability and security of fetching dependency tarballs during the build process. --- .github/workflows/manylinux.yml | 2 +- setup.py | 30 ++++++++++++++++++++---------- 2 files changed, 21 insertions(+), 11 deletions(-) diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 550a8b34..04645e84 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -32,7 +32,7 @@ jobs: - name: Build linux_x86_64 wheel env: PYXMLSEC_STATIC_DEPS: true - PYXMLSEC_LIBXML2_VERSION: 2.14.6 # Lock it to libxml2 2.14.6 until the issue with 2.15.x is resolved; e.g. https://github.com/lsh123/xmlsec/issues/948 + PYXMLSEC_LIBXML2_VERSION: 2.14.6 # Lock it to libxml2 2.14.6 to match it with lxml GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | /opt/python/${{ matrix.python-abi }}/bin/python -m build diff --git a/setup.py b/setup.py index 94b49aa8..014476ca 100644 --- a/setup.py +++ b/setup.py @@ -14,7 +14,7 @@ from distutils.version import StrictVersion as Version from pathlib import Path from urllib.parse import urljoin -from urllib.request import Request, urlcleanup, urlopen, urlretrieve +from urllib.request import Request, urlcleanup, urlopen from setuptools import Extension, setup from setuptools.command.build_ext import build_ext as build_ext_orig @@ -106,6 +106,16 @@ def latest_xmlsec_release(): return tar_gz['browser_download_url'] +def download_lib(url, filename): + req = Request(url, headers={'User-Agent': 'python-xmlsec build'}) + with urlopen(req) as r, open(filename, 'wb') as f: + while True: + chunk = r.read(8192) + if not chunk: + break + f.write(chunk) + + class CrossCompileInfo: def __init__(self, host, arch, compiler): self.host = host @@ -234,7 +244,7 @@ def prepare_static_build_win(self): else: self.info(f'Retrieving "{url}" to "{destfile}"') urlcleanup() # work around FTP bug 27973 in Py2.7.12+ - urlretrieve(url, str(destfile)) + download_lib(url, str(destfile)) for p in self.libs_dir.glob('*.zip'): with zipfile.ZipFile(str(p)) as f: @@ -297,7 +307,7 @@ def prepare_static_build(self, build_platform): else: url = f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{self.openssl_version}' self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) - urlretrieve(url, str(openssl_tar)) + download_lib(url, str(openssl_tar)) # fetch zlib zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) @@ -310,7 +320,7 @@ def prepare_static_build(self, build_platform): else: url = f'https://zlib.net/fossils/zlib-{self.zlib_version}.tar.gz' self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_ZLIB_VERSION={self.zlib_version}, downloading from {url}')) - urlretrieve(url, str(zlib_tar)) + download_lib(url, str(zlib_tar)) # fetch libiconv libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) @@ -319,13 +329,13 @@ def prepare_static_build(self, build_platform): libiconv_tar = self.libs_dir / 'libiconv.tar.gz' if self.libiconv_version is None: url = latest_libiconv_release() - self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {url}')) + self.info('{:10}: {}'.format('libiconv', f'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {url}')) else: url = f'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{self.libiconv_version}.tar.gz' self.info( - '{:10}: {}'.format('zlib', f'PYXMLSEC_LIBICONV_VERSION={self.libiconv_version}, downloading from {url}') + '{:10}: {}'.format('libiconv', f'PYXMLSEC_LIBICONV_VERSION={self.libiconv_version}, downloading from {url}') ) - urlretrieve(url, str(libiconv_tar)) + download_lib(url, str(libiconv_tar)) # fetch libxml2 libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.xz'), None) @@ -341,7 +351,7 @@ def prepare_static_build(self, build_platform): '{:10}: {}'.format('libxml2', f'PYXMLSEC_LIBXML2_VERSION={self.libxml2_version}, downloading from {url}') ) libxml2_tar = self.libs_dir / 'libxml2.tar.xz' - urlretrieve(url, str(libxml2_tar)) + download_lib(url, str(libxml2_tar)) # fetch libxslt libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) @@ -357,7 +367,7 @@ def prepare_static_build(self, build_platform): '{:10}: {}'.format('libxslt', f'PYXMLSEC_LIBXSLT_VERSION={self.libxslt_version}, downloading from {url}') ) libxslt_tar = self.libs_dir / 'libxslt.tar.gz' - urlretrieve(url, str(libxslt_tar)) + download_lib(url, str(libxslt_tar)) # fetch xmlsec1 xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) @@ -372,7 +382,7 @@ def prepare_static_build(self, build_platform): '{:10}: {}'.format('xmlsec1', f'PYXMLSEC_XMLSEC1_VERSION={self.xmlsec1_version}, downloading from {url}') ) xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' - urlretrieve(url, str(xmlsec1_tar)) + download_lib(url, str(xmlsec1_tar)) for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): self.info(f'Unpacking {file.name}') From 8d51c090a633cc52c178e7e89781696be4669d7b Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 7 Oct 2025 07:47:10 +0200 Subject: [PATCH 368/378] [pre-commit.ci] pre-commit autoupdate (#385) --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2a20f7cb..bbb7e9eb 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.2 + rev: v0.13.3 hooks: - id: ruff args: ["--fix"] From e88d9ce1e2f7b757923c07c53658176c29b7ebb5 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 14 Oct 2025 09:27:37 +0200 Subject: [PATCH 369/378] [pre-commit.ci] pre-commit autoupdate (#386) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.13.3 → v0.14.0](https://github.com/astral-sh/ruff-pre-commit/compare/v0.13.3...v0.14.0) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index bbb7e9eb..94fa772b 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.13.3 + rev: v0.14.0 hooks: - id: ruff args: ["--fix"] From a241c56750f40cacd90090a58ed8277dc5f3254a Mon Sep 17 00:00:00 2001 From: ffgan Date: Thu, 16 Oct 2025 19:39:06 +0800 Subject: [PATCH 370/378] build riscv64 wheel (#387) --- .github/workflows/wheels.yml | 4 ++-- doc/source/requirements.txt | 2 +- pyproject.toml | 5 +++-- requirements-test.txt | 2 +- requirements.txt | 2 +- setup.py | 16 ++++++++++++++-- 6 files changed, 22 insertions(+), 9 deletions(-) diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index f29019f0..d9cad9ce 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -77,7 +77,7 @@ jobs: - uses: actions/checkout@v4 - name: Install cibuildwheel # Nb. keep cibuildwheel version pin consistent with job below - run: pipx install cibuildwheel==2.21.3 + run: pipx install cibuildwheel==3.1.4 - id: set-matrix # Once we have the windows build figured out, it can be added here # by updating the matrix to include windows builds as well. @@ -126,7 +126,7 @@ jobs: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v2.21.3 + uses: pypa/cibuildwheel@v3.1.4 with: only: ${{ matrix.only }} env: diff --git a/doc/source/requirements.txt b/doc/source/requirements.txt index 6b78694a..ffb2b6d3 100644 --- a/doc/source/requirements.txt +++ b/doc/source/requirements.txt @@ -1,4 +1,4 @@ -lxml>=3.8 +lxml==6.0.2 importlib_metadata;python_version < '3.8' packaging Sphinx>=3 diff --git a/pyproject.toml b/pyproject.toml index bb0c459e..2b2d2d04 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,5 +1,5 @@ [build-system] -requires = ["setuptools>=42", "wheel", "setuptools_scm[toml]>=3.4", "pkgconfig>=1.5.1", "lxml>=3.8, !=4.7.0"] +requires = ["setuptools==80.9.0", "wheel", "setuptools_scm[toml]>=3.4", "pkgconfig>=1.5.1", "lxml==6.0.2"] [tool.mypy] files = ['src'] @@ -100,6 +100,7 @@ build-verbosity = 1 build-frontend = "build" skip = [ "pp*", # Skips PyPy builds (pp38-*, pp39-*, etc.) + "*musllinux_riscv64" # maturin and ruff currently don’t support the musl + riscv64 target ] test-command = "pytest -v --color=yes {package}/tests" before-test = "pip install -r requirements-test.txt" @@ -109,7 +110,7 @@ test-skip = "*-macosx_arm64" PYXMLSEC_STATIC_DEPS = "true" [tool.cibuildwheel.linux] -archs = ["x86_64", "aarch64"] +archs = ["x86_64", "aarch64", "riscv64"] environment-pass = [ "PYXMLSEC_LIBXML2_VERSION", "PYXMLSEC_LIBXSLT_VERSION", diff --git a/requirements-test.txt b/requirements-test.txt index 52a31f00..ad135d97 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -2,4 +2,4 @@ pytest==8.4.1 lxml-stubs==0.5.1 -ruff[format]==0.12.3 +ruff[format]==0.13.0 diff --git a/requirements.txt b/requirements.txt index 7aa6718b..8221c374 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1 +1 @@ -lxml==6.0.0 +lxml==6.0.2 diff --git a/setup.py b/setup.py index 014476ca..624169c4 100644 --- a/setup.py +++ b/setup.py @@ -404,9 +404,8 @@ def prepare_static_build(self, build_platform): ldflags.append(env['LDFLAGS']) cross_compiling = False - if build_platform == 'darwin': - import platform + if build_platform == 'darwin': arch = self.plat_name.rsplit('-', 1)[1] if arch != platform.machine() and arch in ('x86_64', 'arm64'): self.info(f'Cross-compiling for {arch}') @@ -423,6 +422,19 @@ def prepare_static_build(self, build_platform): self.info('Building OpenSSL') openssl_dir = next(self.build_libs_dir.glob('openssl-*')) openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] + if platform.machine() == 'riscv64': + # add `no-asm` flag for openssl while build for riscv64 + + # on openssl 3.5.2, When building for riscv64, ASM code is used by default. + # However, this version of the assembly code will report during the build: + + # relocation truncated to fit: R_RISCV_JAL against symbol `AES_set_encrypt_key' defined in .text section in /project/build/tmp/prefix/lib/libcrypto.a(libcrypto-lib-aes-riscv64.o) # noqa: E501 + + # This [line] (https://github.com/openssl/openssl/blob/0893a62353583343eb712adef6debdfbe597c227/crypto/aes/asm/aes-riscv64.pl#L1069) of code cannot be completed normally because the jump address of the static link library used by xmlsec is too large. # noqa: E501 + # may be we can consider filing a related issue with OpenSSL later. + # However, for now, for convenience, we can simply disable ASM for riscv64. + # This will result in some performance degradation, but this is acceptable. + openssl_config_cmd.append('no-asm') if cross_compiling: openssl_config_cmd.insert(0, './Configure') openssl_config_cmd.append(cross_compiling.triplet) From c8b1b6b611f0f7d3f710031f2a1597eb8c2ad4fa Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Fri, 17 Oct 2025 09:28:43 +0200 Subject: [PATCH 371/378] Refactor packaging build helpers into dedicated modules (#388) Split the old monolithic `setup.py` build logic into focused helper modules so that static builds are coordinated by dedicated utilities rather than one giant script. Additional changes: - Use fixed library versions - Use GNU mirror FTP for downloading related libraries --- .github/workflows/wheels.yml | 2 +- .pre-commit-config.yaml | 2 +- build_support/__init__.py | 0 build_support/build_ext.py | 86 +++++ build_support/network.py | 29 ++ build_support/releases.py | 77 +++++ build_support/static_build.py | 453 ++++++++++++++++++++++++++ setup.py | 587 +--------------------------------- 8 files changed, 651 insertions(+), 585 deletions(-) create mode 100644 build_support/__init__.py create mode 100644 build_support/build_ext.py create mode 100644 build_support/network.py create mode 100644 build_support/releases.py create mode 100644 build_support/static_build.py diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index d9cad9ce..1d4564a6 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -110,7 +110,7 @@ jobs: include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} env: - PYXMLSEC_LIBXML2_VERSION: 2.14.5 + PYXMLSEC_LIBXML2_VERSION: 2.14.6 PYXMLSEC_LIBXSLT_VERSION: 1.1.43 steps: diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 94fa772b..8fb6f59f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -31,7 +31,7 @@ repos: rev: v1.18.2 hooks: - id: mypy - exclude: (setup.py|tests/.*.py|doc/.*) + exclude: (setup.py|tests|build_support/.*.py|doc/.*) types: [] files: ^.*.pyi?$ additional_dependencies: [lxml-stubs, types-docutils] diff --git a/build_support/__init__.py b/build_support/__init__.py new file mode 100644 index 00000000..e69de29b diff --git a/build_support/build_ext.py b/build_support/build_ext.py new file mode 100644 index 00000000..c4fb5bc9 --- /dev/null +++ b/build_support/build_ext.py @@ -0,0 +1,86 @@ +import os +import sys +from distutils import log +from distutils.errors import DistutilsError + +from setuptools.command.build_ext import build_ext as build_ext_orig + +from .static_build import CrossCompileInfo, StaticBuildHelper + + +class build_ext(build_ext_orig): + def info(self, message): + self.announce(message, level=log.INFO) + + def run(self): + ext = self.ext_map['xmlsec'] + self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) + self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) + self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True) + + if self.static or sys.platform == 'win32': + helper = StaticBuildHelper(self) + helper.prepare(sys.platform) + else: + import pkgconfig + + try: + config = pkgconfig.parse('xmlsec1') + except OSError as error: + raise DistutilsError('Unable to invoke pkg-config.') from error + except pkgconfig.PackageNotFoundError as error: + raise DistutilsError('xmlsec1 is not installed or not in path.') from error + + if config is None or not config.get('libraries'): + raise DistutilsError('Bad or incomplete result returned from pkg-config.') + + ext.define_macros.extend(config['define_macros']) + ext.include_dirs.extend(config['include_dirs']) + ext.library_dirs.extend(config['library_dirs']) + ext.libraries.extend(config['libraries']) + + import lxml + + ext.include_dirs.extend(lxml.get_include()) + + ext.define_macros.extend( + [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] + ) + for key, value in ext.define_macros: + if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')): + ext.define_macros.remove((key, value)) + ext.define_macros.append((key, f'"{value}"')) + break + + if sys.platform == 'win32': + ext.extra_compile_args.append('/Zi') + else: + ext.extra_compile_args.extend( + [ + '-g', + '-std=c99', + '-fPIC', + '-fno-strict-aliasing', + '-Wno-error=declaration-after-statement', + '-Werror=implicit-function-declaration', + ] + ) + + if self.debug: + ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) + if sys.platform == 'win32': + ext.extra_compile_args.append('/Od') + else: + ext.extra_compile_args.append('-Wall') + ext.extra_compile_args.append('-O0') + else: + if self.size_opt: + if sys.platform == 'win32': + ext.extra_compile_args.append('/Os') + else: + ext.extra_compile_args.append('-Os') + + super().run() + + +__all__ = ('CrossCompileInfo', 'build_ext') diff --git a/build_support/network.py b/build_support/network.py new file mode 100644 index 00000000..7ac0bb5e --- /dev/null +++ b/build_support/network.py @@ -0,0 +1,29 @@ +import contextlib +import json +from urllib.request import Request, urlopen + +DEFAULT_USER_AGENT = 'https://github.com/xmlsec/python-xmlsec' +DOWNLOAD_USER_AGENT = 'python-xmlsec build' + + +def make_request(url, github_token=None, json_response=False): + headers = {'User-Agent': DEFAULT_USER_AGENT} + if github_token: + headers['authorization'] = 'Bearer ' + github_token + request = Request(url, headers=headers) + with contextlib.closing(urlopen(request)) as response: + charset = response.headers.get_content_charset() or 'utf-8' + content = response.read().decode(charset) + if json_response: + return json.loads(content) + return content + + +def download_lib(url, filename): + request = Request(url, headers={'User-Agent': DOWNLOAD_USER_AGENT}) + with urlopen(request) as response, open(filename, 'wb') as target: + while True: + chunk = response.read(8192) + if not chunk: + break + target.write(chunk) diff --git a/build_support/releases.py b/build_support/releases.py new file mode 100644 index 00000000..089162e2 --- /dev/null +++ b/build_support/releases.py @@ -0,0 +1,77 @@ +import html.parser +import os +import re +from distutils import log +from distutils.version import StrictVersion as Version + +from .network import make_request + + +class HrefCollector(html.parser.HTMLParser): + def __init__(self, *args, **kwargs): + super().__init__(*args, **kwargs) + self.hrefs = [] + + def handle_starttag(self, tag, attrs): + if tag == 'a': + for name, value in attrs: + if name == 'href': + self.hrefs.append(value) + + +def latest_release_from_html(url, matcher): + content = make_request(url) + collector = HrefCollector() + collector.feed(content) + hrefs = collector.hrefs + + def comp(text): + try: + return Version(matcher.match(text).groupdict()['version']) + except (AttributeError, ValueError): + return Version('0.0') + + latest = max(hrefs, key=comp) + return f'{url}/{latest}' + + +def latest_release_from_gnome_org_cache(url, lib_name): + cache_url = f'{url}/cache.json' + cache = make_request(cache_url, json_response=True) + latest_version = cache[2][lib_name][-1] + latest_source = cache[1][lib_name][latest_version]['tar.xz'] + return f'{url}/{latest_source}' + + +def latest_release_json_from_github_api(repo): + api_url = f'https://api.github.com/repos/{repo}/releases/latest' + token = os.environ.get('GH_TOKEN') + if token: + log.info('Using GitHub token to avoid rate limiting') + return make_request(api_url, token, json_response=True) + + +def latest_openssl_release(): + return latest_release_json_from_github_api('openssl/openssl')['tarball_url'] + + +def latest_zlib_release(): + return latest_release_from_html('https://zlib.net/fossils', re.compile('zlib-(?P.*).tar.gz')) + + +def latest_libiconv_release(): + return latest_release_from_html('https://ftpmirror.gnu.org/libiconv', re.compile('libiconv-(?P.*).tar.gz')) + + +def latest_libxml2_release(): + return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxml2', 'libxml2') + + +def latest_libxslt_release(): + return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxslt', 'libxslt') + + +def latest_xmlsec_release(): + assets = latest_release_json_from_github_api('lsh123/xmlsec')['assets'] + (tar_gz,) = [asset for asset in assets if asset['name'].endswith('.tar.gz')] + return tar_gz['browser_download_url'] diff --git a/build_support/static_build.py b/build_support/static_build.py new file mode 100644 index 00000000..4a0b98e8 --- /dev/null +++ b/build_support/static_build.py @@ -0,0 +1,453 @@ +import multiprocessing +import os +import platform +import subprocess +import sys +import tarfile +import zipfile +from distutils.errors import DistutilsError +from pathlib import Path +from urllib.parse import urljoin +from urllib.request import urlcleanup + +from .network import download_lib +from .releases import ( + latest_libiconv_release, + latest_libxml2_release, + latest_libxslt_release, + latest_openssl_release, + latest_xmlsec_release, + latest_zlib_release, +) + + +class CrossCompileInfo: + def __init__(self, host, arch, compiler): + self.host = host + self.arch = arch + self.compiler = compiler + + @property + def triplet(self): + return f'{self.host}-{self.arch}-{self.compiler}' + + +class StaticBuildHelper: + def __init__(self, builder): + self.builder = builder + self.ext = builder.ext_map['xmlsec'] + self.info = builder.info + self._prepare_directories() + + def prepare(self, platform_name): + self.info(f'starting static build on {sys.platform}') + if platform_name == 'win32': + self._prepare_windows_build() + elif 'linux' in platform_name or 'darwin' in platform_name: + self._prepare_unix_build(platform_name) + else: + raise DistutilsError(f'Unsupported static build platform: {platform_name}') + + def _prepare_directories(self): + buildroot = Path('build', 'tmp') + + prefix_dir = buildroot / 'prefix' + prefix_dir.mkdir(parents=True, exist_ok=True) + self.prefix_dir = prefix_dir.absolute() + + build_libs_dir = buildroot / 'libs' + build_libs_dir.mkdir(exist_ok=True) + self.build_libs_dir = build_libs_dir + + libs_dir = Path(os.environ.get('PYXMLSEC_LIBS_DIR', 'libs')) + libs_dir.mkdir(exist_ok=True) + self.libs_dir = libs_dir + self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) + + self.builder.prefix_dir = self.prefix_dir + self.builder.build_libs_dir = self.build_libs_dir + self.builder.libs_dir = self.libs_dir + + def _prepare_windows_build(self): + release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' + if platform.machine() == 'ARM64': + suffix = 'win-arm64' + elif sys.maxsize > 2**32: + suffix = 'win64' + else: + suffix = 'win32' + + libs = [ + f'libxml2-2.11.9-3.{suffix}.zip', + f'libxslt-1.1.39.{suffix}.zip', + f'zlib-1.3.1.{suffix}.zip', + f'iconv-1.18-1.{suffix}.zip', + f'openssl-3.0.16.pl1.{suffix}.zip', + f'xmlsec-1.3.7.{suffix}.zip', + ] + + for libfile in libs: + url = urljoin(release_url, libfile) + destfile = self.libs_dir / libfile + if destfile.is_file(): + self.info(f'Using local copy of "{url}"') + else: + self.info(f'Retrieving "{url}" to "{destfile}"') + urlcleanup() + download_lib(url, str(destfile)) + + for package in self.libs_dir.glob('*.zip'): + with zipfile.ZipFile(str(package)) as archive: + destdir = self.build_libs_dir + archive.extractall(path=str(destdir)) + + self.ext.define_macros = [ + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('__XMLSEC_FUNCTION__', '__FUNCTION__'), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', '1'), + ('LIBXSLT_STATIC', 1), + ('XMLSEC_STATIC', 1), + ('inline', '__inline'), + ] + self.ext.libraries = [ + 'libxmlsec_a', + 'libxmlsec-openssl_a', + 'libcrypto', + 'iconv_a', + 'libxslt_a', + 'libexslt_a', + 'libxml2_a', + 'zlib', + 'WS2_32', + 'Advapi32', + 'User32', + 'Gdi32', + 'Crypt32', + ] + self.ext.library_dirs = [str(path.absolute()) for path in self.build_libs_dir.rglob('lib')] + + includes = [path for path in self.build_libs_dir.rglob('include') if path.is_dir()] + includes.append(next(path / 'xmlsec' for path in includes if (path / 'xmlsec').is_dir())) + self.ext.include_dirs = [str(path.absolute()) for path in includes] + + def _prepare_unix_build(self, build_platform): + self._capture_version_overrides() + archives = self._ensure_source_archives() + self._extract_archives(archives) + + env, prefix_arg, ldflags, cross_compile = self._prepare_build_environment(build_platform) + self._build_dependencies(env, prefix_arg, ldflags, cross_compile) + self._configure_extension_for_static(build_platform) + + def _capture_version_overrides(self): + builder = self.builder + builder.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '3.6.0') + builder.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION', '1.18') + builder.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', '2.14.6') + builder.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION', '1.1.43') + builder.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.3.1') + builder.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.3.8') + + def _ensure_source_archives(self): + return [ + self._ensure_source( + name='OpenSSL', + glob='openssl*.tar.gz', + filename='openssl.tar.gz', + version=self.builder.openssl_version, + env_label='PYXMLSEC_OPENSSL_VERSION', + default_url=latest_openssl_release, + version_url=lambda v: f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{v}', + ), + self._ensure_source( + name='zlib', + glob='zlib*.tar.gz', + filename='zlib.tar.gz', + version=self.builder.zlib_version, + env_label='PYXMLSEC_ZLIB_VERSION', + default_url=latest_zlib_release, + version_url=lambda v: f'https://zlib.net/fossils/zlib-{v}.tar.gz', + ), + self._ensure_source( + name='libiconv', + glob='libiconv*.tar.gz', + filename='libiconv.tar.gz', + version=self.builder.libiconv_version, + env_label='PYXMLSEC_LIBICONV_VERSION', + default_url=latest_libiconv_release, + version_url=lambda v: f'https://ftpmirror.gnu.org/libiconv/libiconv-{v}.tar.gz', + ), + self._ensure_source( + name='libxml2', + glob='libxml2*.tar.xz', + filename='libxml2.tar.xz', + version=self.builder.libxml2_version, + env_label='PYXMLSEC_LIBXML2_VERSION', + default_url=latest_libxml2_release, + version_url=lambda v: self._libxml_related_url('libxml2', v), + ), + self._ensure_source( + name='libxslt', + glob='libxslt*.tar.xz', + filename='libxslt.tar.xz', + version=self.builder.libxslt_version, + env_label='PYXMLSEC_LIBXSLT_VERSION', + default_url=latest_libxslt_release, + version_url=lambda v: self._libxml_related_url('libxslt', v), + ), + self._ensure_source( + name='xmlsec1', + glob='xmlsec1*.tar.gz', + filename='xmlsec1.tar.gz', + version=self.builder.xmlsec1_version, + env_label='PYXMLSEC_XMLSEC1_VERSION', + default_url=latest_xmlsec_release, + version_url=lambda v: f'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz', + ), + ] + + def _ensure_source(self, name, glob, filename, version, env_label, default_url, version_url): + archive = next(self.libs_dir.glob(glob), None) + if archive is not None: + return archive + + self.info('{:10}: {}'.format(name, 'source tar not found, downloading ...')) + archive = self.libs_dir / filename + if version is None: + url = default_url() + self.info('{:10}: {}'.format(name, f'{env_label} unset, downloading latest from {url}')) + else: + url = version_url(version) + self.info('{:10}: {}'.format(name, f'{env_label}={version}, downloading from {url}')) + download_lib(url, str(archive)) + return archive + + def _libxml_related_url(self, lib_name, version): + version_prefix, _ = version.rsplit('.', 1) + return f'https://download.gnome.org/sources/{lib_name}/{version_prefix}/{lib_name}-{version}.tar.xz' + + def _extract_archives(self, archives): + for archive in archives: + self.info(f'Unpacking {archive.name}') + try: + with tarfile.open(str(archive)) as tar: + tar.extractall(path=str(self.build_libs_dir)) + except EOFError as error: + raise DistutilsError(f'Bad {archive.name} downloaded; remove it and try again.') from error + + def _prepare_build_environment(self, build_platform): + prefix_arg = f'--prefix={self.prefix_dir}' + env = os.environ.copy() + + cflags = [] + if env.get('CFLAGS'): + cflags.append(env['CFLAGS']) + cflags.append('-fPIC') + + ldflags = [] + if env.get('LDFLAGS'): + ldflags.append(env['LDFLAGS']) + + cross_compile = None + if build_platform == 'darwin': + arch = self.builder.plat_name.rsplit('-', 1)[1] + if arch != platform.machine() and arch in ('x86_64', 'arm64'): + self.info(f'Cross-compiling for {arch}') + cflags.append(f'-arch {arch}') + ldflags.append(f'-arch {arch}') + cross_compile = CrossCompileInfo('darwin64', arch, 'cc') + major_version, _ = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) + if major_version >= 11 and 'MACOSX_DEPLOYMENT_TARGET' not in env: + env['MACOSX_DEPLOYMENT_TARGET'] = '11.0' + + env['CFLAGS'] = ' '.join(cflags) + env['LDFLAGS'] = ' '.join(ldflags) + return env, prefix_arg, ldflags, cross_compile + + def _build_dependencies(self, env, prefix_arg, ldflags, cross_compile): + self._build_openssl(env, prefix_arg, cross_compile) + self._build_zlib(env, prefix_arg) + + host_arg = [f'--host={cross_compile.arch}'] if cross_compile else [] + self._build_libiconv(env, prefix_arg, host_arg) + self._build_libxml2(env, prefix_arg, host_arg) + self._build_libxslt(env, prefix_arg, host_arg) + + ldflags.append('-lpthread') + env['LDFLAGS'] = ' '.join(ldflags) + self._build_xmlsec1(env, prefix_arg, host_arg) + + def _build_openssl(self, env, prefix_arg, cross_compile): + self.info('Building OpenSSL') + openssl_dir = next(self.build_libs_dir.glob('openssl-*')) + openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] + if platform.machine() == 'riscv64': + # openssl(riscv64): disable ASM to avoid R_RISCV_JAL relocation failure on 3.5.2 + # OpenSSL 3.5.2 enables RISC-V64 AES assembly by default. When we statically + # link libcrypto alongside xmlsec, the AES asm path triggers a link-time error: + # relocation truncated to fit: R_RISCV_JAL against symbol `AES_set_encrypt_key' + # in .../libcrypto.a(libcrypto-lib-aes-riscv64.o) + # This appears to stem from a long-range jump emitted by the AES asm generator + # (see aes-riscv64.pl around L1069), which can exceed the JAL reach when objects + # end up far apart in the final static link. + # As a pragmatic workaround, disable ASM on riscv64 (pass `no-asm`) so the + # portable C implementation is used. This unblocks the build at the cost of + # some crypto performance on riscv64 only. + # Refs: + # - https://github.com/openssl/openssl/blob/0893a62/crypto/aes/asm/aes-riscv64.pl#L1069 + openssl_config_cmd.append('no-asm') + if cross_compile: + openssl_config_cmd.insert(0, './Configure') + openssl_config_cmd.append(cross_compile.triplet) + else: + openssl_config_cmd.insert(0, './config') + subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install_sw'], cwd=str(openssl_dir), env=env) + + def _build_zlib(self, env, prefix_arg): + self.info('Building zlib') + zlib_dir = next(self.build_libs_dir.glob('zlib-*')) + subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(zlib_dir), env=env) + + def _build_libiconv(self, env, prefix_arg, host_arg): + self.info('Building libiconv') + libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + *host_arg, + ], + cwd=str(libiconv_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libiconv_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libiconv_dir), env=env) + + def _build_libxml2(self, env, prefix_arg, host_arg): + self.info('Building LibXML2') + libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + '--without-lzma', + '--without-python', + f'--with-iconv={self.prefix_dir}', + f'--with-zlib={self.prefix_dir}', + *host_arg, + ], + cwd=str(libxml2_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxml2_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxml2_dir), env=env) + + def _build_libxslt(self, env, prefix_arg, host_arg): + self.info('Building libxslt') + libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + '--without-python', + '--without-crypto', + f'--with-libxml-prefix={self.prefix_dir}', + *host_arg, + ], + cwd=str(libxslt_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxslt_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxslt_dir), env=env) + + def _build_xmlsec1(self, env, prefix_arg, host_arg): + self.info('Building xmlsec1') + xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-shared', + '--disable-gost', + '--enable-md5', + '--enable-ripemd160', + '--disable-crypto-dl', + '--enable-static=yes', + '--enable-shared=no', + '--enable-static-linking=yes', + '--with-default-crypto=openssl', + f'--with-openssl={self.prefix_dir}', + f'--with-libxml={self.prefix_dir}', + f'--with-libxslt={self.prefix_dir}', + *host_arg, + ], + cwd=str(xmlsec1_dir), + env=env, + ) + include_flags = [ + f'-I{self.prefix_dir / "include"}', + f'-I{self.prefix_dir / "include" / "libxml"}', + ] + subprocess.check_call( + ['make', f'-j{multiprocessing.cpu_count() + 1}', *include_flags], + cwd=str(xmlsec1_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(xmlsec1_dir), env=env) + + def _configure_extension_for_static(self, build_platform): + self.ext.define_macros = [ + ('__XMLSEC_FUNCTION__', '__func__'), + ('XMLSEC_NO_SIZE_T', None), + ('XMLSEC_NO_GOST', '1'), + ('XMLSEC_NO_GOST2012', '1'), + ('XMLSEC_NO_XKMS', '1'), + ('XMLSEC_CRYPTO', '\\"openssl\\"'), + ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), + ('XMLSEC_CRYPTO_OPENSSL', '1'), + ('LIBXML_ICONV_ENABLED', 1), + ('LIBXML_STATIC', 1), + ('LIBXSLT_STATIC', 1), + ('XMLSEC_STATIC', 1), + ('inline', '__inline'), + ('UNICODE', '1'), + ('_UNICODE', '1'), + ] + + self.ext.include_dirs.append(str(self.prefix_dir / 'include')) + self.ext.include_dirs.extend([str(path.absolute()) for path in (self.prefix_dir / 'include').iterdir() if path.is_dir()]) + + self.ext.library_dirs = [] + if build_platform == 'linux': + self.ext.libraries = ['m', 'rt'] + extra_objects = [ + 'libxmlsec1.a', + 'libxslt.a', + 'libxml2.a', + 'libz.a', + 'libxmlsec1-openssl.a', + 'libcrypto.a', + 'libiconv.a', + 'libxmlsec1.a', + ] + self.ext.extra_objects = [str(self.prefix_dir / 'lib' / obj) for obj in extra_objects] + + +__all__ = ('CrossCompileInfo', 'StaticBuildHelper') diff --git a/setup.py b/setup.py index 624169c4..4b3d93f7 100644 --- a/setup.py +++ b/setup.py @@ -1,596 +1,17 @@ -import contextlib -import html.parser -import json -import multiprocessing -import os -import platform -import re -import subprocess -import sys -import tarfile -import zipfile -from distutils import log -from distutils.errors import DistutilsError -from distutils.version import StrictVersion as Version from pathlib import Path -from urllib.parse import urljoin -from urllib.request import Request, urlcleanup, urlopen from setuptools import Extension, setup -from setuptools.command.build_ext import build_ext as build_ext_orig - - -class HrefCollector(html.parser.HTMLParser): - def __init__(self, *args, **kwargs): - super().__init__(*args, **kwargs) - self.hrefs = [] - - def handle_starttag(self, tag, attrs): - if tag == 'a': - for name, value in attrs: - if name == 'href': - self.hrefs.append(value) - - -def make_request(url, github_token=None, json_response=False): - headers = {'User-Agent': 'https://github.com/xmlsec/python-xmlsec'} - if github_token: - headers['authorization'] = 'Bearer ' + github_token - request = Request(url, headers=headers) - with contextlib.closing(urlopen(request)) as r: - charset = r.headers.get_content_charset() or 'utf-8' - content = r.read().decode(charset) - if json_response: - return json.loads(content) - else: - return content - - -def latest_release_from_html(url, matcher): - content = make_request(url) - collector = HrefCollector() - collector.feed(content) - hrefs = collector.hrefs - - def comp(text): - try: - return Version(matcher.match(text).groupdict()['version']) - except (AttributeError, ValueError): - return Version('0.0') - - latest = max(hrefs, key=comp) - return f'{url}/{latest}' - - -def latest_release_from_gnome_org_cache(url, lib_name): - cache_url = f'{url}/cache.json' - cache = make_request(cache_url, json_response=True) - latest_version = cache[2][lib_name][-1] - latest_source = cache[1][lib_name][latest_version]['tar.xz'] - return f'{url}/{latest_source}' - - -def latest_release_json_from_github_api(repo): - api_url = f'https://api.github.com/repos/{repo}/releases/latest' - - # if we are running in CI, pass along the GH_TOKEN, so we don't get rate limited - token = os.environ.get('GH_TOKEN') - if token: - log.info('Using GitHub token to avoid rate limiting') - return make_request(api_url, token, json_response=True) - - -def latest_openssl_release(): - return latest_release_json_from_github_api('openssl/openssl')['tarball_url'] - - -def latest_zlib_release(): - return latest_release_from_html('https://zlib.net/fossils', re.compile('zlib-(?P.*).tar.gz')) - - -def latest_libiconv_release(): - return latest_release_from_html('https://ftp.gnu.org/pub/gnu/libiconv', re.compile('libiconv-(?P.*).tar.gz')) - - -def latest_libxml2_release(): - return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxml2', 'libxml2') - - -def latest_libxslt_release(): - return latest_release_from_gnome_org_cache('https://download.gnome.org/sources/libxslt', 'libxslt') - - -def latest_xmlsec_release(): - assets = latest_release_json_from_github_api('lsh123/xmlsec')['assets'] - (tar_gz,) = [asset for asset in assets if asset['name'].endswith('.tar.gz')] - return tar_gz['browser_download_url'] - - -def download_lib(url, filename): - req = Request(url, headers={'User-Agent': 'python-xmlsec build'}) - with urlopen(req) as r, open(filename, 'wb') as f: - while True: - chunk = r.read(8192) - if not chunk: - break - f.write(chunk) - - -class CrossCompileInfo: - def __init__(self, host, arch, compiler): - self.host = host - self.arch = arch - self.compiler = compiler - - @property - def triplet(self): - return f'{self.host}-{self.arch}-{self.compiler}' - - -class build_ext(build_ext_orig): - def info(self, message): - self.announce(message, level=log.INFO) - - def run(self): - ext = self.ext_map['xmlsec'] - self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) - self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) - self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True) - - if self.static or sys.platform == 'win32': - self.info(f'starting static build on {sys.platform}') - buildroot = Path('build', 'tmp') - - self.prefix_dir = buildroot / 'prefix' - self.prefix_dir.mkdir(parents=True, exist_ok=True) - self.prefix_dir = self.prefix_dir.absolute() - - self.build_libs_dir = buildroot / 'libs' - self.build_libs_dir.mkdir(exist_ok=True) - - self.libs_dir = Path(os.environ.get('PYXMLSEC_LIBS_DIR', 'libs')) - self.libs_dir.mkdir(exist_ok=True) - self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) - - if sys.platform == 'win32': - self.prepare_static_build_win() - elif 'linux' in sys.platform or 'darwin' in sys.platform: - self.prepare_static_build(sys.platform) - else: - import pkgconfig - - try: - config = pkgconfig.parse('xmlsec1') - except OSError as e: - raise DistutilsError('Unable to invoke pkg-config.') from e - except pkgconfig.PackageNotFoundError as e: - raise DistutilsError('xmlsec1 is not installed or not in path.') from e - - if config is None or not config.get('libraries'): - raise DistutilsError('Bad or incomplete result returned from pkg-config.') - - ext.define_macros.extend(config['define_macros']) - ext.include_dirs.extend(config['include_dirs']) - ext.library_dirs.extend(config['library_dirs']) - ext.libraries.extend(config['libraries']) - - import lxml - - ext.include_dirs.extend(lxml.get_include()) - - ext.define_macros.extend( - [('MODULE_NAME', self.distribution.metadata.name), ('MODULE_VERSION', self.distribution.metadata.version)] - ) - # escape the XMLSEC_CRYPTO macro value, see mehcode/python-xmlsec#141 - for key, value in ext.define_macros: - if key == 'XMLSEC_CRYPTO' and not (value.startswith('"') and value.endswith('"')): - ext.define_macros.remove((key, value)) - ext.define_macros.append((key, f'"{value}"')) - break - - if sys.platform == 'win32': - ext.extra_compile_args.append('/Zi') - else: - ext.extra_compile_args.extend( - [ - '-g', - '-std=c99', - '-fPIC', - '-fno-strict-aliasing', - '-Wno-error=declaration-after-statement', - '-Werror=implicit-function-declaration', - ] - ) - - if self.debug: - ext.define_macros.append(('PYXMLSEC_ENABLE_DEBUG', '1')) - if sys.platform == 'win32': - ext.extra_compile_args.append('/Od') - else: - ext.extra_compile_args.append('-Wall') - ext.extra_compile_args.append('-O0') - else: - if self.size_opt: - if sys.platform == 'win32': - ext.extra_compile_args.append('/Os') - else: - ext.extra_compile_args.append('-Os') - - super().run() - - def prepare_static_build_win(self): - release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' - if platform.machine() == 'ARM64': - suffix = 'win-arm64' - elif sys.maxsize > 2**32: # 2.0 GiB - suffix = 'win64' - else: - suffix = 'win32' - - libs = [ - f'libxml2-2.11.9-3.{suffix}.zip', - f'libxslt-1.1.39.{suffix}.zip', - f'zlib-1.3.1.{suffix}.zip', - f'iconv-1.18-1.{suffix}.zip', - f'openssl-3.0.16.pl1.{suffix}.zip', - f'xmlsec-1.3.7.{suffix}.zip', - ] - - for libfile in libs: - url = urljoin(release_url, libfile) - destfile = self.libs_dir / libfile - if destfile.is_file(): - self.info(f'Using local copy of "{url}"') - else: - self.info(f'Retrieving "{url}" to "{destfile}"') - urlcleanup() # work around FTP bug 27973 in Py2.7.12+ - download_lib(url, str(destfile)) - - for p in self.libs_dir.glob('*.zip'): - with zipfile.ZipFile(str(p)) as f: - destdir = self.build_libs_dir - f.extractall(path=str(destdir)) - - ext = self.ext_map['xmlsec'] - ext.define_macros = [ - ('XMLSEC_CRYPTO', '\\"openssl\\"'), - ('__XMLSEC_FUNCTION__', '__FUNCTION__'), - ('XMLSEC_NO_GOST', '1'), - ('XMLSEC_NO_XKMS', '1'), - ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), - ('XMLSEC_CRYPTO_OPENSSL', '1'), - ('UNICODE', '1'), - ('_UNICODE', '1'), - ('LIBXML_ICONV_ENABLED', 1), - ('LIBXML_STATIC', '1'), - ('LIBXSLT_STATIC', '1'), - ('XMLSEC_STATIC', '1'), - ('inline', '__inline'), - ] - ext.libraries = [ - 'libxmlsec_a', - 'libxmlsec-openssl_a', - 'libcrypto', - 'iconv_a', - 'libxslt_a', - 'libexslt_a', - 'libxml2_a', - 'zlib', - 'WS2_32', - 'Advapi32', - 'User32', - 'Gdi32', - 'Crypt32', - ] - ext.library_dirs = [str(p.absolute()) for p in self.build_libs_dir.rglob('lib')] - - includes = [p for p in self.build_libs_dir.rglob('include') if p.is_dir()] - includes.append(next(p / 'xmlsec' for p in includes if (p / 'xmlsec').is_dir())) - ext.include_dirs = [str(p.absolute()) for p in includes] - - def prepare_static_build(self, build_platform): - self.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION') - self.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION') - self.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION') - self.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION') - self.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION') - self.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION') - - # fetch openssl - openssl_tar = next(self.libs_dir.glob('openssl*.tar.gz'), None) - if openssl_tar is None: - self.info('{:10}: {}'.format('OpenSSL', 'source tar not found, downloading ...')) - openssl_tar = self.libs_dir / 'openssl.tar.gz' - if self.openssl_version is None: - url = latest_openssl_release() - self.info('{:10}: {}'.format('OpenSSL', f'PYXMLSEC_OPENSSL_VERSION unset, downloading latest from {url}')) - else: - url = f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{self.openssl_version}' - self.info('{:10}: {} {}'.format('OpenSSL', 'version', self.openssl_version)) - download_lib(url, str(openssl_tar)) - - # fetch zlib - zlib_tar = next(self.libs_dir.glob('zlib*.tar.gz'), None) - if zlib_tar is None: - self.info('{:10}: {}'.format('zlib', 'source not found, downloading ...')) - zlib_tar = self.libs_dir / 'zlib.tar.gz' - if self.zlib_version is None: - url = latest_zlib_release() - self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_ZLIB_VERSION unset, downloading latest from {url}')) - else: - url = f'https://zlib.net/fossils/zlib-{self.zlib_version}.tar.gz' - self.info('{:10}: {}'.format('zlib', f'PYXMLSEC_ZLIB_VERSION={self.zlib_version}, downloading from {url}')) - download_lib(url, str(zlib_tar)) - - # fetch libiconv - libiconv_tar = next(self.libs_dir.glob('libiconv*.tar.gz'), None) - if libiconv_tar is None: - self.info('{:10}: {}'.format('libiconv', 'source not found, downloading ...')) - libiconv_tar = self.libs_dir / 'libiconv.tar.gz' - if self.libiconv_version is None: - url = latest_libiconv_release() - self.info('{:10}: {}'.format('libiconv', f'PYXMLSEC_LIBICONV_VERSION unset, downloading latest from {url}')) - else: - url = f'https://ftp.gnu.org/pub/gnu/libiconv/libiconv-{self.libiconv_version}.tar.gz' - self.info( - '{:10}: {}'.format('libiconv', f'PYXMLSEC_LIBICONV_VERSION={self.libiconv_version}, downloading from {url}') - ) - download_lib(url, str(libiconv_tar)) - - # fetch libxml2 - libxml2_tar = next(self.libs_dir.glob('libxml2*.tar.xz'), None) - if libxml2_tar is None: - self.info('{:10}: {}'.format('libxml2', 'source tar not found, downloading ...')) - if self.libxml2_version is None: - url = latest_libxml2_release() - self.info('{:10}: {}'.format('libxml2', f'PYXMLSEC_LIBXML2_VERSION unset, downloading latest from {url}')) - else: - version_prefix, _ = self.libxml2_version.rsplit('.', 1) - url = f'https://download.gnome.org/sources/libxml2/{version_prefix}/libxml2-{self.libxml2_version}.tar.xz' - self.info( - '{:10}: {}'.format('libxml2', f'PYXMLSEC_LIBXML2_VERSION={self.libxml2_version}, downloading from {url}') - ) - libxml2_tar = self.libs_dir / 'libxml2.tar.xz' - download_lib(url, str(libxml2_tar)) - - # fetch libxslt - libxslt_tar = next(self.libs_dir.glob('libxslt*.tar.gz'), None) - if libxslt_tar is None: - self.info('{:10}: {}'.format('libxslt', 'source tar not found, downloading ...')) - if self.libxslt_version is None: - url = latest_libxslt_release() - self.info('{:10}: {}'.format('libxslt', f'PYXMLSEC_LIBXSLT_VERSION unset, downloading latest from {url}')) - else: - version_prefix, _ = self.libxslt_version.rsplit('.', 1) - url = f'https://download.gnome.org/sources/libxslt/{version_prefix}/libxslt-{self.libxslt_version}.tar.xz' - self.info( - '{:10}: {}'.format('libxslt', f'PYXMLSEC_LIBXSLT_VERSION={self.libxslt_version}, downloading from {url}') - ) - libxslt_tar = self.libs_dir / 'libxslt.tar.gz' - download_lib(url, str(libxslt_tar)) - - # fetch xmlsec1 - xmlsec1_tar = next(self.libs_dir.glob('xmlsec1*.tar.gz'), None) - if xmlsec1_tar is None: - self.info('{:10}: {}'.format('xmlsec1', 'source tar not found, downloading ...')) - if self.xmlsec1_version is None: - url = latest_xmlsec_release() - self.info('{:10}: {}'.format('xmlsec1', f'PYXMLSEC_XMLSEC1_VERSION unset, downloading latest from {url}')) - else: - url = f'https://github.com/lsh123/xmlsec/releases/download/{self.xmlsec1_version}/xmlsec1-{self.xmlsec1_version}.tar.gz' - self.info( - '{:10}: {}'.format('xmlsec1', f'PYXMLSEC_XMLSEC1_VERSION={self.xmlsec1_version}, downloading from {url}') - ) - xmlsec1_tar = self.libs_dir / 'xmlsec1.tar.gz' - download_lib(url, str(xmlsec1_tar)) - - for file in (openssl_tar, zlib_tar, libiconv_tar, libxml2_tar, libxslt_tar, xmlsec1_tar): - self.info(f'Unpacking {file.name}') - try: - with tarfile.open(str(file)) as tar: - tar.extractall(path=str(self.build_libs_dir)) - except EOFError as e: - raise DistutilsError(f'Bad {file.name} downloaded; remove it and try again.') from e - - prefix_arg = f'--prefix={self.prefix_dir}' - - env = os.environ.copy() - cflags = [] - if env.get('CFLAGS'): - cflags.append(env['CFLAGS']) - cflags.append('-fPIC') - ldflags = [] - if env.get('LDFLAGS'): - ldflags.append(env['LDFLAGS']) - - cross_compiling = False - - if build_platform == 'darwin': - arch = self.plat_name.rsplit('-', 1)[1] - if arch != platform.machine() and arch in ('x86_64', 'arm64'): - self.info(f'Cross-compiling for {arch}') - cflags.append(f'-arch {arch}') - ldflags.append(f'-arch {arch}') - cross_compiling = CrossCompileInfo('darwin64', arch, 'cc') - major_version, _ = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) - if major_version >= 11 and 'MACOSX_DEPLOYMENT_TARGET' not in env: - env['MACOSX_DEPLOYMENT_TARGET'] = '11.0' - - env['CFLAGS'] = ' '.join(cflags) - env['LDFLAGS'] = ' '.join(ldflags) - - self.info('Building OpenSSL') - openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] - if platform.machine() == 'riscv64': - # add `no-asm` flag for openssl while build for riscv64 - - # on openssl 3.5.2, When building for riscv64, ASM code is used by default. - # However, this version of the assembly code will report during the build: - - # relocation truncated to fit: R_RISCV_JAL against symbol `AES_set_encrypt_key' defined in .text section in /project/build/tmp/prefix/lib/libcrypto.a(libcrypto-lib-aes-riscv64.o) # noqa: E501 - - # This [line] (https://github.com/openssl/openssl/blob/0893a62353583343eb712adef6debdfbe597c227/crypto/aes/asm/aes-riscv64.pl#L1069) of code cannot be completed normally because the jump address of the static link library used by xmlsec is too large. # noqa: E501 - # may be we can consider filing a related issue with OpenSSL later. - # However, for now, for convenience, we can simply disable ASM for riscv64. - # This will result in some performance degradation, but this is acceptable. - openssl_config_cmd.append('no-asm') - if cross_compiling: - openssl_config_cmd.insert(0, './Configure') - openssl_config_cmd.append(cross_compiling.triplet) - else: - openssl_config_cmd.insert(0, './config') - subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(openssl_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install_sw'], cwd=str(openssl_dir), env=env) - - self.info('Building zlib') - zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(zlib_dir), env=env) - - host_arg = [] - if cross_compiling: - host_arg = [f'--host={cross_compiling.arch}'] - - self.info('Building libiconv') - libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - *host_arg, - ], - cwd=str(libiconv_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libiconv_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libiconv_dir), env=env) - - self.info('Building LibXML2') - libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - '--without-lzma', - '--without-python', - f'--with-iconv={self.prefix_dir}', - f'--with-zlib={self.prefix_dir}', - *host_arg, - ], - cwd=str(libxml2_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxml2_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxml2_dir), env=env) - - self.info('Building libxslt') - libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - '--without-python', - '--without-crypto', - f'--with-libxml-prefix={self.prefix_dir}', - *host_arg, - ], - cwd=str(libxslt_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxslt_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxslt_dir), env=env) - - self.info('Building xmlsec1') - ldflags.append('-lpthread') - env['LDFLAGS'] = ' '.join(ldflags) - xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-shared', - '--disable-gost', - '--enable-md5', - '--enable-ripemd160', - '--disable-crypto-dl', - '--enable-static=yes', - '--enable-shared=no', - '--enable-static-linking=yes', - '--with-default-crypto=openssl', - f'--with-openssl={self.prefix_dir}', - f'--with-libxml={self.prefix_dir}', - f'--with-libxslt={self.prefix_dir}', - *host_arg, - ], - cwd=str(xmlsec1_dir), - env=env, - ) - include_flags = [ - f'-I{self.prefix_dir / "include"}', - f'-I{self.prefix_dir / "include" / "libxml"}', - ] - subprocess.check_call( - ['make', f'-j{multiprocessing.cpu_count() + 1}', *include_flags], - cwd=str(xmlsec1_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(xmlsec1_dir), env=env) - - ext = self.ext_map['xmlsec'] - ext.define_macros = [ - ('__XMLSEC_FUNCTION__', '__func__'), - ('XMLSEC_NO_SIZE_T', None), - ('XMLSEC_NO_GOST', '1'), - ('XMLSEC_NO_GOST2012', '1'), - ('XMLSEC_NO_XKMS', '1'), - ('XMLSEC_CRYPTO', '\\"openssl\\"'), - ('XMLSEC_NO_CRYPTO_DYNAMIC_LOADING', '1'), - ('XMLSEC_CRYPTO_OPENSSL', '1'), - ('LIBXML_ICONV_ENABLED', 1), - ('LIBXML_STATIC', '1'), - ('LIBXSLT_STATIC', '1'), - ('XMLSEC_STATIC', '1'), - ('inline', '__inline'), - ('UNICODE', '1'), - ('_UNICODE', '1'), - ] - - ext.include_dirs.append(str(self.prefix_dir / 'include')) - ext.include_dirs.extend([str(p.absolute()) for p in (self.prefix_dir / 'include').iterdir() if p.is_dir()]) - - ext.library_dirs = [] - if build_platform == 'linux': - ext.libraries = ['m', 'rt'] - extra_objects = [ - 'libxmlsec1.a', - 'libxslt.a', - 'libxml2.a', - 'libz.a', - 'libxmlsec1-openssl.a', - 'libcrypto.a', - 'libiconv.a', - 'libxmlsec1.a', - ] - ext.extra_objects = [str(self.prefix_dir / 'lib' / o) for o in extra_objects] +from build_support.build_ext import build_ext src_root = Path(__file__).parent / 'src' -sources = [str(p.absolute()) for p in src_root.rglob('*.c')] +sources = [str(path.absolute()) for path in src_root.rglob('*.c')] pyxmlsec = Extension('xmlsec', sources=sources) setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] -with open('README.md', encoding='utf-8') as f: - long_desc = f.read() +with open('README.md', encoding='utf-8') as readme: + long_desc = readme.read() setup( From 47f3e00c2e351ad663a753e68c7c13b780627ef7 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 21 Oct 2025 12:12:56 +0200 Subject: [PATCH 372/378] [pre-commit.ci] pre-commit autoupdate (#389) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.0 → v0.14.1](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.0...v0.14.1) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 8fb6f59f..3dc8df2d 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.0 + rev: v0.14.1 hooks: - id: ruff args: ["--fix"] From c42bf925d7eb7acdab0a892e326c7690fb009de1 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 28 Oct 2025 13:52:15 +0100 Subject: [PATCH 373/378] [pre-commit.ci] pre-commit autoupdate (#391) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.1 → v0.14.2](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.1...v0.14.2) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 3dc8df2d..2a91f0ab 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.1 + rev: v0.14.2 hooks: - id: ruff args: ["--fix"] From 1bb232462fcb2b3b726a3b5443f30f34e34b9a5c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Cl=C3=A9ment=20Escolano?= Date: Fri, 31 Oct 2025 15:54:13 +0100 Subject: [PATCH 374/378] Add support for Python 3.14 (#393) --- .github/workflows/linuxbrew.yml | 2 +- .github/workflows/macosx.yml | 2 +- .github/workflows/manylinux.yml | 2 +- .github/workflows/sdist.yml | 2 +- .travis.yml | 1 + pyproject.toml | 3 ++- setup.py | 1 + 7 files changed, 8 insertions(+), 5 deletions(-) diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 8a231047..1c6d9543 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] env: # For some unknown reason, linuxbrew tries to use "gcc-11" by default, which doesn't exist. CC: gcc diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index 44d214bc..e2e2a0df 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -8,7 +8,7 @@ jobs: runs-on: macos-latest strategy: matrix: - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] static_deps: ["static", ""] steps: - uses: actions/checkout@v3 diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index 04645e84..d1c205d7 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -8,7 +8,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-abi: [cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313] + python-abi: [cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313, cp314-cp314] image: - manylinux2014_x86_64 - manylinux_2_28_x86_64 diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index 3bdc9764..ecc53c31 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -12,7 +12,7 @@ jobs: runs-on: ubuntu-22.04 strategy: matrix: - python: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] steps: - uses: actions/checkout@v3 - name: Set up Python diff --git a/.travis.yml b/.travis.yml index 9574a1c7..8d3ca07e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -14,6 +14,7 @@ python: - "3.11" - "3.12" - "3.13" + - "3.14" env: global: diff --git a/pyproject.toml b/pyproject.toml index 2b2d2d04..7c7b4bf3 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -94,7 +94,8 @@ build = [ "cp310-*", "cp311-*", "cp312-*", - "cp313-*" + "cp313-*", + "cp314-*" ] build-verbosity = 1 build-frontend = "build" diff --git a/setup.py b/setup.py index 4b3d93f7..4100a52b 100644 --- a/setup.py +++ b/setup.py @@ -50,6 +50,7 @@ 'Programming Language :: Python :: 3.11', 'Programming Language :: Python :: 3.12', 'Programming Language :: Python :: 3.13', + 'Programming Language :: Python :: 3.14', 'Topic :: Text Processing :: Markup :: XML', 'Typing :: Typed', ], From 60a0788e4359de80591a1c78bbf161325a7b1078 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 4 Nov 2025 10:26:11 +0100 Subject: [PATCH 375/378] [pre-commit.ci] pre-commit autoupdate (#394) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.2 → v0.14.3](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.2...v0.14.3) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 2a91f0ab..49a3a0da 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.2 + rev: v0.14.3 hooks: - id: ruff args: ["--fix"] From 47d4201def5d9d131b4f4a29088d677fab8a19f4 Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 10 Nov 2025 11:12:09 +0100 Subject: [PATCH 376/378] Bump xmlsec1 library to v1.3.9 (#398) --- build_support/static_build.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build_support/static_build.py b/build_support/static_build.py index 4a0b98e8..09e2039a 100644 --- a/build_support/static_build.py +++ b/build_support/static_build.py @@ -153,7 +153,7 @@ def _capture_version_overrides(self): builder.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', '2.14.6') builder.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION', '1.1.43') builder.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.3.1') - builder.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.3.8') + builder.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.3.9') def _ensure_source_archives(self): return [ From 8d98ff24fbf03f530c3178e013ba42c8afc0d26f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 11 Nov 2025 13:11:53 +0100 Subject: [PATCH 377/378] [pre-commit.ci] pre-commit autoupdate (#399) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit updates: - [github.com/astral-sh/ruff-pre-commit: v0.14.3 → v0.14.4](https://github.com/astral-sh/ruff-pre-commit/compare/v0.14.3...v0.14.4) Co-authored-by: pre-commit-ci[bot] <66853113+pre-commit-ci[bot]@users.noreply.github.com> --- .pre-commit-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 49a3a0da..aca65390 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -2,7 +2,7 @@ # See https://pre-commit.com/hooks.html for more hooks repos: - repo: https://github.com/astral-sh/ruff-pre-commit - rev: v0.14.3 + rev: v0.14.4 hooks: - id: ruff args: ["--fix"] From 6a61caea84d283f27903b2bab5f84fd043ad293c Mon Sep 17 00:00:00 2001 From: Amin Solhizadeh Date: Mon, 16 Feb 2026 16:00:13 +0100 Subject: [PATCH 378/378] Refactor static dependency builder and cache dependency archives in CI (#401) Extract static dependency preparation into a reusable builder and wire CI to reuse downloaded archives across jobs/platforms. This reduces duplicated build logic, improves maintainability, and speeds up wheel/sdist workflows. - Introduce `build_support/lib_xmlsec_dependency_builder.py`: - Centralize dependency version resolution, source/archive download, extract, and build steps for OpenSSL, zlib, libiconv, libxml2, libxslt, and xmlsec1. - Support both Unix and Windows dependency preparation paths. - Preserve cross-compilation handling via `CrossCompileInfo` (now a dataclass). - Expose resolved library versions for callers. - Add `build_libs_xmlsec.py` CLI: - Provide a standalone entrypoint to prepare dependencies. - Support `--download-only`, custom `--libs-dir`, custom `--buildroot`, and target platform/plat-name overrides. - Refactor `build_support/static_build.py`: - Delegate dependency preparation to `LibXmlsecDependencyBuilder`. - Keep extension configuration focused on platform-specific compiler/linker flags and include/lib wiring. - Preserve static-link behavior while removing duplicated dependency logic. - Update `build_support/build_ext.py`: - Initialize build flags (`PYXMLSEC_ENABLE_DEBUG`, `PYXMLSEC_STATIC_DEPS`, `PYXMLSEC_OPTIMIZE_SIZE`) in `__init__`. - Keep build flow unchanged, but use the refactored static helper path. - Modernize packaging metadata: - Move project metadata from `setup.py` into PEP 621 fields in `pyproject.toml` (`[project]`, `[project.urls]`, `[tool.setuptools]`). - Simplify `setup.py` to extension setup only. - Delete legacy `setup.cfg`. - Relax build-system pins and align build requirements with setuptools_scm>=8. - Bump `ruff[format]` in `requirements-test.txt` to `0.14.4`. - Add reusable dependency-cache workflow: - New `.github/workflows/cache_libs.yml` workflow_call job that downloads and caches `libs/*.{xz,gz,zip}` per OS/arch/version inputs. - Export cache/version outputs for downstream jobs. - Validate expected Windows archive filenames. - Rework wheel/manylinux CI to consume cached libs: - `manylinux.yml` now depends on `cache_libs`, restores cache, and runs build + test inside container via new script `.github/scripts/manylinux_build_and_test.sh`. - Script sets `PYTHONPATH` and `PYXMLSEC_LIBS_DIR` explicitly so isolated PEP 517 builds can import local helpers and reuse cached archives. - `wheels.yml` now depends on `cache_libs`, restores cache before cibuildwheel, updates action versions, and refreshes matrix generation (`generate_wheels_matrix`) including ARM Linux runner mapping. - `sdist.yml` installs `setuptools_scm>=8` during build deps setup. - Use cached libs for macOS static build - Minor workflow hygiene updates: - Normalize formatting and small ordering/conditional tweaks in `linuxbrew.yml` and `macosx.yml`. --- .github/scripts/manylinux_build_and_test.sh | 52 +++ .github/workflows/cache_libs.yml | 134 ++++++ .github/workflows/linuxbrew.yml | 8 + .github/workflows/macosx.yml | 48 +- .github/workflows/manylinux.yml | 74 ++-- .github/workflows/sdist.yml | 13 +- .github/workflows/wheels.yml | 65 +-- build_libs_xmlsec.py | 55 +++ build_support/build_ext.py | 11 +- .../lib_xmlsec_dependency_builder.py | 417 ++++++++++++++++++ build_support/static_build.py | 378 +--------------- pyproject.toml | 74 +++- requirements-test.txt | 2 +- setup.cfg | 22 - setup.py | 48 +- 15 files changed, 895 insertions(+), 506 deletions(-) create mode 100644 .github/scripts/manylinux_build_and_test.sh create mode 100644 .github/workflows/cache_libs.yml create mode 100644 build_libs_xmlsec.py create mode 100644 build_support/lib_xmlsec_dependency_builder.py delete mode 100644 setup.cfg diff --git a/.github/scripts/manylinux_build_and_test.sh b/.github/scripts/manylinux_build_and_test.sh new file mode 100644 index 00000000..01c6867f --- /dev/null +++ b/.github/scripts/manylinux_build_and_test.sh @@ -0,0 +1,52 @@ +#!/bin/sh +set -eu + +: "${PY_ABI:?PY_ABI is required}" +: "${MANYLINUX_IMAGE:?MANYLINUX_IMAGE is required}" + +# Make local build helpers importable for isolated PEP 517 backend subprocesses. +export PYTHONPATH="$PWD${PYTHONPATH:+:${PYTHONPATH}}" +# Ensure dependency archives are read from the restored workspace cache even in isolated builds. +export PYXMLSEC_LIBS_DIR="$PWD/libs" + +# Step: Install system build dependencies (manylinux only) +echo "== [container] Step: Install system build dependencies (manylinux only) ==" +case "$MANYLINUX_IMAGE" in + manylinux*) + yum install -y perl-core + ;; +esac + +# Step: Install python build dependencies +echo "== [container] Step: Install python build dependencies ==" +/opt/python/${PY_ABI}/bin/pip install --upgrade pip setuptools wheel build 'setuptools_scm>=8' + +# Step: Set environment variables +echo "== [container] Step: Set environment variables ==" +PKGVER=$(/opt/python/${PY_ABI}/bin/python setup.py --version) +echo "PKGVER=$PKGVER" + +# Step: Build linux_x86_64 wheel +echo "== [container] Step: Build linux_x86_64 wheel ==" +/opt/python/${PY_ABI}/bin/python -m build + +# Step: Label manylinux wheel +echo "== [container] Step: Label manylinux wheel ==" +ls -la dist/ +auditwheel show dist/xmlsec-${PKGVER}-${PY_ABI}-linux_x86_64.whl +auditwheel repair dist/xmlsec-${PKGVER}-${PY_ABI}-linux_x86_64.whl +ls -la wheelhouse/ +auditwheel show wheelhouse/xmlsec-${PKGVER}-${PY_ABI}-*${MANYLINUX_IMAGE}*.whl + +# Step: Install test dependencies +echo "== [container] Step: Install test dependencies ==" +/opt/python/${PY_ABI}/bin/pip install --upgrade -r requirements-test.txt +/opt/python/${PY_ABI}/bin/pip install xmlsec --only-binary=xmlsec --no-index --find-links=wheelhouse/ + +# Step: Run tests +echo "== [container] Step: Run tests ==" +/opt/python/${PY_ABI}/bin/pytest -v --color=yes + +# Step: Fix mounted workspace file ownership on host +echo "== [container] Step: Fix mounted workspace file ownership on host ==" +chown -R "${HOST_UID}:${HOST_GID}" dist wheelhouse build libs || true diff --git a/.github/workflows/cache_libs.yml b/.github/workflows/cache_libs.yml new file mode 100644 index 00000000..77c83353 --- /dev/null +++ b/.github/workflows/cache_libs.yml @@ -0,0 +1,134 @@ +name: Cache library dependencies + +on: + workflow_call: + inputs: + LIBICONV_VERSION: + default: "1.18" + required: false + type: string + LIBXML2_VERSION: + default: "2.14.6" + required: false + type: string + LIBXSLT_VERSION: + default: "1.1.43" + required: false + type: string + OPENSSL_VERSION: + default: "3.6.0" + required: false + type: string + XMLSEC1_VERSION: + default: "1.3.9" + required: false + type: string + ZLIB_VERSION: + default: "1.3.1" + required: false + type: string + WIN_LIBICONV_VERSION: + default: "1.18-1" + required: false + type: string + WIN_LIBXML2_VERSION: + default: "2.11.9-3" + required: false + type: string + WIN_LIBXSLT_VERSION: + default: "1.1.39" + required: false + type: string + WIN_OPENSSL_VERSION: + default: "3.0.16.pl1" + required: false + type: string + WIN_XMLSEC1_VERSION: + default: "1.3.7" + required: false + type: string + WIN_ZLIB_VERSION: + default: "1.3.1" + required: false + type: string + + outputs: + LIBICONV_VERSION: + value: ${{ inputs.LIBICONV_VERSION }} + LIBXML2_VERSION: + value: ${{ inputs.LIBXML2_VERSION }} + LIBXSLT_VERSION: + value: ${{ inputs.LIBXSLT_VERSION }} + OPENSSL_VERSION: + value: ${{ inputs.OPENSSL_VERSION }} + XMLSEC1_VERSION: + value: ${{ inputs.XMLSEC1_VERSION }} + ZLIB_VERSION: + value: ${{ inputs.ZLIB_VERSION }} + WIN_LIBICONV_VERSION: + value: ${{ inputs.WIN_LIBICONV_VERSION }} + WIN_LIBXML2_VERSION: + value: ${{ inputs.WIN_LIBXML2_VERSION }} + WIN_LIBXSLT_VERSION: + value: ${{ inputs.WIN_LIBXSLT_VERSION }} + WIN_OPENSSL_VERSION: + value: ${{ inputs.WIN_OPENSSL_VERSION }} + WIN_XMLSEC1_VERSION: + value: ${{ inputs.WIN_XMLSEC1_VERSION }} + WIN_ZLIB_VERSION: + value: ${{ inputs.WIN_ZLIB_VERSION }} + +jobs: + cache_libs: + strategy: + fail-fast: false + matrix: + os: + - "ubuntu-22.04" + - "ubuntu-22.04-arm" + - "macos-latest" + - "windows-2022" + - "windows-11-arm" + + runs-on: ${{ matrix.os }} + + env: + LIBICONV_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_LIBICONV_VERSION || inputs.LIBICONV_VERSION }} + LIBXML2_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_LIBXML2_VERSION || inputs.LIBXML2_VERSION }} + LIBXSLT_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_LIBXSLT_VERSION || inputs.LIBXSLT_VERSION }} + OPENSSL_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_OPENSSL_VERSION || inputs.OPENSSL_VERSION }} + XMLSEC1_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_XMLSEC1_VERSION || inputs.XMLSEC1_VERSION }} + ZLIB_VERSION: ${{ contains(matrix.os, 'windows-') && inputs.WIN_ZLIB_VERSION || inputs.ZLIB_VERSION }} + + steps: + - uses: actions/checkout@v6 + + - name: Cache [libs] + uses: actions/cache@v4.3.0 + with: + path: | + libs/*.xz + libs/*.gz + libs/*.zip + key: libs-${{ runner.os }}-${{ runner.arch }}-${{ env.LIBXML2_VERSION }}-${{ env.LIBXSLT_VERSION }} + + - uses: actions/setup-python@v6 + with: + python-version: "3.13" + + - name: Install setuptools shim + run: python -m pip install --upgrade pip setuptools + + - name: Download latest libraries + env: + GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: python build_libs_xmlsec.py --download-only + + - name: Check Windows library versions + if: ${{ contains(matrix.os, 'windows-') }} + run: | + bash -c ' + for file in libs/iconv-${{ inputs.WIN_LIBICONV_VERSION }}.*.zip libs/libxml2-${{ inputs.WIN_LIBXML2_VERSION }}.*.zip libs/libxslt-${{ inputs.WIN_LIBXSLT_VERSION }}.*.zip libs/openssl-${{ inputs.WIN_OPENSSL_VERSION }}.*.zip libs/xmlsec-${{ inputs.WIN_XMLSEC1_VERSION }}.*.zip libs/zlib-${{ inputs.WIN_ZLIB_VERSION }}.*.zip; do + [[ -f "$file" ]] || { echo "MISSING: $file" ; exit 1; } + done + ' diff --git a/.github/workflows/linuxbrew.yml b/.github/workflows/linuxbrew.yml index 1c6d9543..51b0db1e 100644 --- a/.github/workflows/linuxbrew.yml +++ b/.github/workflows/linuxbrew.yml @@ -3,27 +3,34 @@ on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_name != 'master' }} + jobs: linuxbrew: runs-on: ubuntu-latest + strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + env: # For some unknown reason, linuxbrew tries to use "gcc-11" by default, which doesn't exist. CC: gcc + steps: - uses: actions/checkout@v3 + - name: Install brew run: | sudo apt install -y build-essential procps curl file git /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/HEAD/install.sh)" echo "/home/linuxbrew/.linuxbrew/bin" >> $GITHUB_PATH + - name: Install build dependencies run: | brew update brew install python@${{ matrix.python }} gcc libxml2 libxmlsec1 pkg-config echo "/home/linuxbrew/.linuxbrew/opt/python@${{ matrix.python }}/libexec/bin" >> $GITHUB_PATH + - name: Build wheel run: | python3 -m venv build_venv @@ -33,6 +40,7 @@ jobs: export LDFLAGS="-L$(brew --prefix)/lib" python3 -m build rm -rf build/ + - name: Run tests run: | python3 -m venv test_venv diff --git a/.github/workflows/macosx.yml b/.github/workflows/macosx.yml index e2e2a0df..522a2a0a 100644 --- a/.github/workflows/macosx.yml +++ b/.github/workflows/macosx.yml @@ -3,23 +3,47 @@ on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_name != 'master' }} + jobs: + cache_libs: + uses: ./.github/workflows/cache_libs.yml + secrets: inherit + macosx: + needs: cache_libs runs-on: macos-latest + + env: + LIBXML2_VERSION: ${{ needs.cache_libs.outputs.LIBXML2_VERSION }} + LIBXSLT_VERSION: ${{ needs.cache_libs.outputs.LIBXSLT_VERSION }} + strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] static_deps: ["static", ""] + steps: - - uses: actions/checkout@v3 - - name: Setup Python - uses: actions/setup-python@v4 + - uses: actions/checkout@v5.0.0 + + - name: Cache [libs] + id: cache-libs + uses: actions/cache/restore@v4.3.0 + with: + path: | + libs/*.xz + libs/*.gz + libs/*.zip + key: libs-${{ runner.os }}-${{ runner.arch }}-${{ env.LIBXML2_VERSION }}-${{ env.LIBXSLT_VERSION }} + + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + - name: Install build dependencies run: | pip install --upgrade pip setuptools wheel build brew install libxml2 libxmlsec1 pkg-config + - name: Build macosx_x86_64 wheel env: CC: clang @@ -29,26 +53,38 @@ jobs: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" - export PYXMLSEC_LIBXML2_VERSION="$(pkg-config --modversion libxml-2.0)" + export PYXMLSEC_LIBS_DIR="$PWD/libs" python -m build rm -rf build/ + - name: Set environment variables shell: bash run: | echo "PKGVER=$(python setup.py --version)" >> $GITHUB_ENV echo "LLVM_PROFILE_FILE=pyxmlsec.profraw" >> $GITHUB_ENV - - name: Install test dependencies + + - name: Install test dependencies (static only) + if: matrix.static_deps == 'static' + run: | + pip install coverage --upgrade -r requirements-test.txt + pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ + + + - name: Install test dependencies (non-static only) + if: matrix.static_deps != 'static' run: | export PKG_CONFIG_PATH="$(brew --prefix)/opt/libxml2/lib/pkgconfig" pip install coverage --upgrade --no-binary=lxml -r requirements-test.txt pip install xmlsec --only-binary=xmlsec --no-index --find-links=dist/ echo "PYXMLSEC_LIBFILE=$(python -c 'import xmlsec; print(xmlsec.__file__)')" >> $GITHUB_ENV + - name: Run tests run: | coverage run -m pytest -v --color=yes + - name: Report coverage to codecov + if: matrix.static_deps != 'static' run: | /Library/Developer/CommandLineTools/usr/bin/llvm-profdata merge -sparse ${{ env.LLVM_PROFILE_FILE }} -output pyxmlsec.profdata /Library/Developer/CommandLineTools/usr/bin/llvm-cov show ${{ env.PYXMLSEC_LIBFILE }} --arch=$(uname -m) --instr-profile=pyxmlsec.profdata src > coverage.txt bash <(curl -s https://codecov.io/bash) -f coverage.txt - if: matrix.static_deps != 'static' diff --git a/.github/workflows/manylinux.yml b/.github/workflows/manylinux.yml index d1c205d7..ff04f9ae 100644 --- a/.github/workflows/manylinux.yml +++ b/.github/workflows/manylinux.yml @@ -3,9 +3,20 @@ on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_name != 'master' }} + jobs: + cache_libs: + uses: ./.github/workflows/cache_libs.yml + secrets: inherit + manylinux: + needs: cache_libs runs-on: ubuntu-latest + + env: + LIBXML2_VERSION: ${{ needs.cache_libs.outputs.LIBXML2_VERSION }} + LIBXSLT_VERSION: ${{ needs.cache_libs.outputs.LIBXSLT_VERSION }} + strategy: matrix: python-abi: [cp39-cp39, cp310-cp310, cp311-cp311, cp312-cp312, cp313-cp313, cp314-cp314] @@ -13,40 +24,39 @@ jobs: - manylinux2014_x86_64 - manylinux_2_28_x86_64 - musllinux_1_2_x86_64 - container: quay.io/pypa/${{ matrix.image }} + steps: - - uses: actions/checkout@v1 - - name: Install python build dependencies - run: | - # https://github.com/actions/runner/issues/2033 - chown -R $(id -u):$(id -g) $PWD - /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade pip setuptools wheel build - - name: Install system build dependencies (manylinux) - run: | - yum install -y perl-core - if: contains(matrix.image, 'manylinux') - - name: Set environment variables - shell: bash - run: | - echo "PKGVER=$(/opt/python/${{ matrix.python-abi }}/bin/python setup.py --version)" >> $GITHUB_ENV - - name: Build linux_x86_64 wheel + - uses: actions/checkout@v5.0.0 + with: + fetch-depth: 0 + + - name: Cache [libs] + uses: actions/cache/restore@v4.3.0 + with: + path: | + libs/*.xz + libs/*.gz + libs/*.zip + key: libs-${{ runner.os }}-${{ runner.arch }}-${{ env.LIBXML2_VERSION }}-${{ env.LIBXSLT_VERSION }} + + # Keep this job on the host runner so JS-based actions (for example actions/cache) + # can run, then execute build/test inside the target manylinux/musllinux container. + - name: Build and test in container env: PYXMLSEC_STATIC_DEPS: true - PYXMLSEC_LIBXML2_VERSION: 2.14.6 # Lock it to libxml2 2.14.6 to match it with lxml GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} + PY_ABI: ${{ matrix.python-abi }} + MANYLINUX_IMAGE: ${{ matrix.image }} run: | - /opt/python/${{ matrix.python-abi }}/bin/python -m build - - name: Label manylinux wheel - run: | - ls -la dist/ - auditwheel show dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl - auditwheel repair dist/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-linux_x86_64.whl - ls -la wheelhouse/ - auditwheel show wheelhouse/xmlsec-${{ env.PKGVER }}-${{ matrix.python-abi }}-*${{ matrix.image }}*.whl - - name: Install test dependencies - run: | - /opt/python/${{ matrix.python-abi }}/bin/pip install --upgrade -r requirements-test.txt - /opt/python/${{ matrix.python-abi }}/bin/pip install xmlsec --only-binary=xmlsec --no-index --find-links=wheelhouse/ - - name: Run tests - run: | - /opt/python/${{ matrix.python-abi }}/bin/pytest -v --color=yes + set -euxo pipefail + docker run --rm \ + -v "$PWD:$PWD" \ + -w "$PWD" \ + -e GH_TOKEN \ + -e PYXMLSEC_STATIC_DEPS \ + -e PY_ABI \ + -e MANYLINUX_IMAGE \ + -e HOST_UID="$(id -u)" \ + -e HOST_GID="$(id -g)" \ + "quay.io/pypa/${MANYLINUX_IMAGE}" \ + sh .github/scripts/manylinux_build_and_test.sh diff --git a/.github/workflows/sdist.yml b/.github/workflows/sdist.yml index ecc53c31..f48ca02c 100644 --- a/.github/workflows/sdist.yml +++ b/.github/workflows/sdist.yml @@ -3,6 +3,7 @@ on: [push, pull_request] concurrency: group: ${{ github.workflow }}-${{ github.ref }} cancel-in-progress: ${{ github.ref_name != 'master' }} + jobs: sdist: # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev @@ -10,27 +11,33 @@ jobs: # (It thinks the softhsm engine has a public key instead of a private key.) # libxmlsec1 <=1.2.33 or >=1.2.42 works. TODO: Try 26.04 when available. runs-on: ubuntu-22.04 + strategy: matrix: python: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] + steps: - uses: actions/checkout@v3 - - name: Set up Python - uses: actions/setup-python@v4 + + - uses: actions/setup-python@v4 with: python-version: ${{ matrix.python }} + - name: Install build dependencies run: | - pip install --upgrade pip setuptools wheel + pip install --upgrade pip setuptools wheel 'setuptools_scm>=8' + - name: Package source dist run: | python setup.py sdist + - name: Install test dependencies run: | sudo apt-get update sudo apt-get install libxml2-dev libxmlsec1-dev libxmlsec1-openssl opensc softhsm2 libengine-pkcs11-openssl pip install --upgrade -r requirements-test.txt --no-binary lxml pip install dist/xmlsec-$(python setup.py --version).tar.gz + - name: Run tests run: | pytest -v --color=yes diff --git a/.github/workflows/wheels.yml b/.github/workflows/wheels.yml index 1d4564a6..fa80a645 100644 --- a/.github/workflows/wheels.yml +++ b/.github/workflows/wheels.yml @@ -22,6 +22,10 @@ concurrency: permissions: {} jobs: + cache_libs: + uses: ./.github/workflows/cache_libs.yml + secrets: inherit + sdist: # Avoid Ubuntu 24.04 in sdist workflows, because it contains libxmlsec1-dev # v1.2.39, which has a bug that causes tests/test_pkcs11.py to fail. @@ -33,18 +37,18 @@ jobs: contents: write steps: - - uses: actions/checkout@v4.1.1 + - uses: actions/checkout@v5.0.0 with: fetch-depth: 0 - name: Set up Python - uses: actions/setup-python@v5.0.0 + uses: actions/setup-python@v6.0.0 with: - python-version: "3.x" + python-version: '3.14' - name: Install build dependencies run: | - pip install --upgrade pip setuptools wheel + pip install --upgrade pip setuptools wheel setuptools_scm>=8 pkgconfig>=1.5.1 - name: Package source dist run: python setup.py sdist @@ -60,34 +64,35 @@ jobs: run: pytest -v --color=yes - name: Upload sdist - uses: actions/upload-artifact@v4.3.1 + uses: actions/upload-artifact@v5.0.0 with: name: sdist path: dist/*.tar.gz - generate-wheels-matrix: + generate_wheels_matrix: # Create a matrix of all architectures & versions to build. # This enables the next step to run cibuildwheel in parallel. # From https://iscinumpy.dev/post/cibuildwheel-2-10-0/#only-210 name: Generate wheels matrix - runs-on: ubuntu-latest + runs-on: ubuntu-24.04 + outputs: include: ${{ steps.set-matrix.outputs.include }} + steps: - - uses: actions/checkout@v4 + - uses: actions/checkout@v5.0.0 + - name: Install cibuildwheel - # Nb. keep cibuildwheel version pin consistent with job below - run: pipx install cibuildwheel==3.1.4 + # N.B. Keep cibuildwheel version pin consistent with "build_wheels" job below. + run: pipx install cibuildwheel==3.3 + - id: set-matrix - # Once we have the windows build figured out, it can be added here - # by updating the matrix to include windows builds as well. - # See example here: - # https://github.com/lxml/lxml/blob/3ccc7d583e325ceb0ebdf8fc295bbb7fc8cd404d/.github/workflows/wheels.yml#L95C1-L106C51 run: | MATRIX=$( { cibuildwheel --print-build-identifiers --platform linux \ - | jq -nRc '{"only": inputs, "os": "ubuntu-latest"}' \ + | jq -nRc '{"only": inputs, "os": "ubuntu-22.04"}' \ + | sed -e '/aarch64/s|ubuntu-22.04|ubuntu-22.04-arm|' \ && cibuildwheel --print-build-identifiers --platform macos \ | jq -nRc '{"only": inputs, "os": "macos-latest"}' \ && cibuildwheel --print-build-identifiers --platform windows \ @@ -101,38 +106,48 @@ jobs: build_wheels: name: Build for ${{ matrix.only }} - needs: generate-wheels-matrix + needs: [cache_libs, generate_wheels_matrix] runs-on: ${{ matrix.os }} + env: + LIBXML2_VERSION: ${{ contains(matrix.os, 'windows-') && needs.cache_libs.outputs.WIN_LIBXML2_VERSION || needs.cache_libs.outputs.LIBXML2_VERSION }} + LIBXSLT_VERSION: ${{ contains(matrix.os, 'windows-') && needs.cache_libs.outputs.WIN_LIBXSLT_VERSION || needs.cache_libs.outputs.LIBXSLT_VERSION }} + strategy: fail-fast: false matrix: - include: ${{ fromJson(needs.generate-wheels-matrix.outputs.include) }} - - env: - PYXMLSEC_LIBXML2_VERSION: 2.14.6 - PYXMLSEC_LIBXSLT_VERSION: 1.1.43 + include: ${{ fromJson(needs.generate_wheels_matrix.outputs.include) }} steps: - name: Check out the repo - uses: actions/checkout@v4 + uses: actions/checkout@v5.0.0 with: fetch-depth: 0 + - name: Cache [libs] + uses: actions/cache/restore@v4.3.0 + with: + path: | + libs/*.xz + libs/*.gz + libs/*.zip + key: libs-${{ runner.os }}-${{ runner.arch }}-${{ env.LIBXML2_VERSION }}-${{ env.LIBXSLT_VERSION }} + - name: Set up QEMU if: runner.os == 'Linux' - uses: docker/setup-qemu-action@v3 + uses: docker/setup-qemu-action@v3.7.0 with: platforms: all - name: Build wheels - uses: pypa/cibuildwheel@v3.1.4 + uses: pypa/cibuildwheel@v3.3.0 with: only: ${{ matrix.only }} env: GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - - uses: actions/upload-artifact@v4.3.1 + - name: Upload wheels + uses: actions/upload-artifact@v5.0.0 with: path: ./wheelhouse/*.whl name: xmlsec-wheel-${{ matrix.only }} diff --git a/build_libs_xmlsec.py b/build_libs_xmlsec.py new file mode 100644 index 00000000..a4a7e603 --- /dev/null +++ b/build_libs_xmlsec.py @@ -0,0 +1,55 @@ +import argparse +import os +import sys +from pathlib import Path + +from build_support.lib_xmlsec_dependency_builder import LibXmlsecDependencyBuilder + + +def _console_info(message): + print(message) + + +def main(argv=None): + parser = argparse.ArgumentParser(description='Download and build static dependency libraries for python-xmlsec.') + parser.add_argument( + '--platform', + default=sys.platform, + help='Target platform (default: current interpreter platform).', + ) + parser.add_argument( + '--plat-name', + default=os.environ.get('PYXMLSEC_PLAT_NAME'), + help='Target platform tag for cross-compiling (for example macosx-11.0-arm64).', + ) + parser.add_argument( + '--libs-dir', + default=os.environ.get('PYXMLSEC_LIBS_DIR', 'libs'), + help='Directory where source/binary archives are stored.', + ) + parser.add_argument( + '--buildroot', + default=Path('build', 'tmp'), + type=Path, + help='Build root for extracted/build artifacts.', + ) + parser.add_argument( + '--download-only', + action='store_true', + help='Only download dependency archives; do not extract/build.', + ) + + args = parser.parse_args(argv) + builder = LibXmlsecDependencyBuilder( + platform_name=args.platform, + info=_console_info, + libs_dir=Path(args.libs_dir), + buildroot=args.buildroot, + plat_name=args.plat_name, + ) + builder.prepare(download_only=args.download_only) + return 0 + + +if __name__ == '__main__': + raise SystemExit(main()) diff --git a/build_support/build_ext.py b/build_support/build_ext.py index c4fb5bc9..262acd97 100644 --- a/build_support/build_ext.py +++ b/build_support/build_ext.py @@ -9,15 +9,18 @@ class build_ext(build_ext_orig): - def info(self, message): - self.announce(message, level=log.INFO) + def __init__(self, *args, **kwargs) -> None: + super().__init__(*args, **kwargs) - def run(self): - ext = self.ext_map['xmlsec'] self.debug = os.environ.get('PYXMLSEC_ENABLE_DEBUG', False) self.static = os.environ.get('PYXMLSEC_STATIC_DEPS', False) self.size_opt = os.environ.get('PYXMLSEC_OPTIMIZE_SIZE', True) + def info(self, message) -> None: + self.announce(message, level=log.INFO) + + def run(self) -> None: + ext = self.ext_map['xmlsec'] if self.static or sys.platform == 'win32': helper = StaticBuildHelper(self) helper.prepare(sys.platform) diff --git a/build_support/lib_xmlsec_dependency_builder.py b/build_support/lib_xmlsec_dependency_builder.py new file mode 100644 index 00000000..00b519dd --- /dev/null +++ b/build_support/lib_xmlsec_dependency_builder.py @@ -0,0 +1,417 @@ +import multiprocessing +import os +import platform +import subprocess +import sys +import tarfile +import zipfile +from dataclasses import dataclass +from distutils.errors import DistutilsError +from pathlib import Path +from typing import ClassVar +from urllib.parse import urljoin +from urllib.request import urlcleanup + +from .network import download_lib +from .releases import ( + latest_libiconv_release, + latest_libxml2_release, + latest_libxslt_release, + latest_openssl_release, + latest_xmlsec_release, + latest_zlib_release, +) + + +@dataclass +class CrossCompileInfo: + host: str + arch: str + compiler: str + + @property + def triplet(self) -> str: + return f'{self.host}-{self.arch}-{self.compiler}' + + +class LibXmlsecDependencyBuilder: + WINDOWS_LIBS_DOWNLOAD_RELEASE_URL = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' + LIB_VERSION_ENV_VARS: ClassVar[dict[str, str]] = { + 'libiconv_version': 'PYXMLSEC_LIBICONV_VERSION', + 'libxml2_version': 'PYXMLSEC_LIBXML2_VERSION', + 'libxslt_version': 'PYXMLSEC_LIBXSLT_VERSION', + 'openssl_version': 'PYXMLSEC_OPENSSL_VERSION', + 'xmlsec1_version': 'PYXMLSEC_XMLSEC1_VERSION', + 'zlib_version': 'PYXMLSEC_ZLIB_VERSION', + } + UNIX_DEFAULT_LIB_VERSIONS: ClassVar[dict[str, str]] = { + 'libiconv_version': '1.18', + 'libxml2_version': '2.14.6', # Make sure it matches with lxml + 'libxslt_version': '1.1.43', + 'openssl_version': '3.6.0', + 'xmlsec1_version': '1.3.9', + 'zlib_version': '1.3.1', + } + WINDOWS_DEFAULT_LIB_VERSIONS: ClassVar[dict[str, str]] = { + 'libiconv_version': '1.18-1', + 'libxml2_version': '2.11.9-3', # Make sure it matches with lxml + 'libxslt_version': '1.1.39', + 'openssl_version': '3.0.16.pl1', + 'xmlsec1_version': '1.3.7', + 'zlib_version': '1.3.1', + } + + def __init__(self, platform_name, info=None, libs_dir=None, buildroot=None, plat_name=None): + self.platform_name = platform_name + self.info = info or print + self.plat_name = plat_name + + self._prepare_directories(libs_dir=libs_dir, buildroot=buildroot) + self._set_library_versions(build_platform=platform_name) + + @property + def versions(self): + return {attr: getattr(self, attr) for attr in self.LIB_VERSION_ENV_VARS} + + def prepare(self, download_only=False): + self.info(f'preparing dependency build on {self.platform_name}') + if self.platform_name == 'win32': + self._prepare_windows_build(download_only=download_only) + elif 'linux' in self.platform_name or 'darwin' in self.platform_name: + self._prepare_unix_build(build_platform=self.platform_name, download_only=download_only) + else: + raise DistutilsError(f'Unsupported static build platform: {self.platform_name}') + + def _prepare_directories(self, libs_dir=None, buildroot=None): + buildroot_path = Path(buildroot) if buildroot else Path('build', 'tmp') + + prefix_dir = buildroot_path / 'prefix' + prefix_dir.mkdir(parents=True, exist_ok=True) + self.prefix_dir = prefix_dir.absolute() + + build_libs_dir = buildroot_path / 'libs' + build_libs_dir.mkdir(parents=True, exist_ok=True) + self.build_libs_dir = build_libs_dir + + libs_root = libs_dir if libs_dir is not None else os.environ.get('PYXMLSEC_LIBS_DIR', 'libs') + libs_dir_path = Path(libs_root) + libs_dir_path.mkdir(parents=True, exist_ok=True) + self.libs_dir = libs_dir_path + + self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) + + def _set_library_versions(self, build_platform): + defaults = self.UNIX_DEFAULT_LIB_VERSIONS + if build_platform == 'win32': + defaults = self.WINDOWS_DEFAULT_LIB_VERSIONS + + for version_attr, env_var in self.LIB_VERSION_ENV_VARS.items(): + setattr(self, version_attr, os.environ.get(env_var, defaults[version_attr])) + + def _prepare_windows_build(self, download_only=False): + if platform.machine() == 'ARM64': + suffix = 'win-arm64' + elif sys.maxsize > 2**32: + suffix = 'win64' + else: + suffix = 'win32' + + libs = [ + f'libxml2-{self.libxml2_version}.{suffix}.zip', + f'libxslt-{self.libxslt_version}.{suffix}.zip', + f'zlib-{self.zlib_version}.{suffix}.zip', + f'iconv-{self.libiconv_version}.{suffix}.zip', + f'openssl-{self.openssl_version}.{suffix}.zip', + f'xmlsec-{self.xmlsec1_version}.{suffix}.zip', + ] + + for libfile in libs: + url = urljoin(self.WINDOWS_LIBS_DOWNLOAD_RELEASE_URL, libfile) + destfile = self.libs_dir / libfile + if destfile.is_file(): + self.info(f'Using local copy of "{url}"') + else: + self.info(f'Retrieving "{url}" to "{destfile}"') + urlcleanup() + download_lib(url, str(destfile)) + + if download_only: + return + + for package in self.libs_dir.glob('*.zip'): + with zipfile.ZipFile(str(package)) as archive: + archive.extractall(path=str(self.build_libs_dir)) + + def _prepare_unix_build(self, build_platform, download_only=False): + archives = self._ensure_source_archives() + if download_only: + return + + self._extract_archives(archives) + + env, prefix_arg, ldflags, cross_compile = self._prepare_build_environment(build_platform) + self._build_dependencies(env, prefix_arg, ldflags, cross_compile) + + def _ensure_source_archives(self): + return [ + self._ensure_source( + name='OpenSSL', + glob='openssl*.tar.gz', + filename='openssl.tar.gz', + version=self.openssl_version, + env_label='PYXMLSEC_OPENSSL_VERSION', + default_url=latest_openssl_release, + version_url=lambda v: f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{v}', + ), + self._ensure_source( + name='zlib', + glob='zlib*.tar.gz', + filename='zlib.tar.gz', + version=self.zlib_version, + env_label='PYXMLSEC_ZLIB_VERSION', + default_url=latest_zlib_release, + version_url=lambda v: f'https://zlib.net/fossils/zlib-{v}.tar.gz', + ), + self._ensure_source( + name='libiconv', + glob='libiconv*.tar.gz', + filename='libiconv.tar.gz', + version=self.libiconv_version, + env_label='PYXMLSEC_LIBICONV_VERSION', + default_url=latest_libiconv_release, + version_url=lambda v: f'https://ftpmirror.gnu.org/libiconv/libiconv-{v}.tar.gz', + ), + self._ensure_source( + name='libxml2', + glob='libxml2*.tar.xz', + filename='libxml2.tar.xz', + version=self.libxml2_version, + env_label='PYXMLSEC_LIBXML2_VERSION', + default_url=latest_libxml2_release, + version_url=lambda v: self._libxml_related_url('libxml2', v), + ), + self._ensure_source( + name='libxslt', + glob='libxslt*.tar.xz', + filename='libxslt.tar.xz', + version=self.libxslt_version, + env_label='PYXMLSEC_LIBXSLT_VERSION', + default_url=latest_libxslt_release, + version_url=lambda v: self._libxml_related_url('libxslt', v), + ), + self._ensure_source( + name='xmlsec1', + glob='xmlsec1*.tar.gz', + filename='xmlsec1.tar.gz', + version=self.xmlsec1_version, + env_label='PYXMLSEC_XMLSEC1_VERSION', + default_url=latest_xmlsec_release, + version_url=lambda v: f'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz', + ), + ] + + def _ensure_source(self, name, glob, filename, version, env_label, default_url, version_url): + archive = next(self.libs_dir.glob(glob), None) + if archive is not None: + return archive + + self.info('{:10}: {}'.format(name, 'source tar not found, downloading ...')) + archive = self.libs_dir / filename + if version is None: + url = default_url() + self.info('{:10}: {}'.format(name, f'{env_label} unset, downloading latest from {url}')) + else: + url = version_url(version) + self.info('{:10}: {}'.format(name, f'{env_label}={version}, downloading from {url}')) + download_lib(url, str(archive)) + return archive + + def _libxml_related_url(self, lib_name, version): + version_prefix, _ = version.rsplit('.', 1) + return f'https://download.gnome.org/sources/{lib_name}/{version_prefix}/{lib_name}-{version}.tar.xz' + + def _extract_archives(self, archives): + for archive in archives: + self.info(f'Unpacking {archive.name}') + try: + with tarfile.open(str(archive)) as tar: + if sys.version_info >= (3, 12): + tar.extractall(path=str(self.build_libs_dir), filter='data') + else: + tar.extractall(path=str(self.build_libs_dir)) + except EOFError as error: + raise DistutilsError(f'Bad {archive.name} downloaded; remove it and try again.') from error + + def _prepare_build_environment(self, build_platform): + prefix_arg = f'--prefix={self.prefix_dir}' + env = os.environ.copy() + + cflags = [] + if env.get('CFLAGS'): + cflags.append(env['CFLAGS']) + cflags.append('-fPIC') + + ldflags = [] + if env.get('LDFLAGS'): + ldflags.append(env['LDFLAGS']) + + cross_compile = None + if build_platform == 'darwin': + if self.plat_name: + arch = self.plat_name.rsplit('-', 1)[1] + if arch != platform.machine() and arch in ('x86_64', 'arm64'): + self.info(f'Cross-compiling for {arch}') + cflags.append(f'-arch {arch}') + ldflags.append(f'-arch {arch}') + cross_compile = CrossCompileInfo('darwin64', arch, 'cc') + major_version, _ = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) + if major_version >= 11 and 'MACOSX_DEPLOYMENT_TARGET' not in env: + env['MACOSX_DEPLOYMENT_TARGET'] = '11.0' + + env['CFLAGS'] = ' '.join(cflags) + env['LDFLAGS'] = ' '.join(ldflags) + return env, prefix_arg, ldflags, cross_compile + + def _build_dependencies(self, env, prefix_arg, ldflags, cross_compile): + self._build_openssl(env, prefix_arg, cross_compile) + self._build_zlib(env, prefix_arg) + + host_arg = [f'--host={cross_compile.arch}'] if cross_compile else [] + self._build_libiconv(env, prefix_arg, host_arg) + self._build_libxml2(env, prefix_arg, host_arg) + self._build_libxslt(env, prefix_arg, host_arg) + + ldflags.append('-lpthread') + env['LDFLAGS'] = ' '.join(ldflags) + self._build_xmlsec1(env, prefix_arg, host_arg) + + def _build_openssl(self, env, prefix_arg, cross_compile): + self.info('Building OpenSSL') + openssl_dir = next(self.build_libs_dir.glob('openssl-*')) + openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] + if platform.machine() == 'riscv64': + # openssl(riscv64): disable ASM to avoid R_RISCV_JAL relocation failure on 3.5.2 + # OpenSSL 3.5.2 enables RISC-V64 AES assembly by default. When we statically + # link libcrypto alongside xmlsec, the AES asm path triggers a link-time error: + # relocation truncated to fit: R_RISCV_JAL against symbol `AES_set_encrypt_key' + # in .../libcrypto.a(libcrypto-lib-aes-riscv64.o) + # This appears to stem from a long-range jump emitted by the AES asm generator + # (see aes-riscv64.pl around L1069), which can exceed the JAL reach when objects + # end up far apart in the final static link. + # As a pragmatic workaround, disable ASM on riscv64 (pass `no-asm`) so the + # portable C implementation is used. This unblocks the build at the cost of + # some crypto performance on riscv64 only. + # Refs: + # - https://github.com/openssl/openssl/blob/0893a62/crypto/aes/asm/aes-riscv64.pl#L1069 + openssl_config_cmd.append('no-asm') + if cross_compile: + openssl_config_cmd.insert(0, './Configure') + openssl_config_cmd.append(cross_compile.triplet) + else: + openssl_config_cmd.insert(0, './config') + subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(openssl_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install_sw'], cwd=str(openssl_dir), env=env) + + def _build_zlib(self, env, prefix_arg): + self.info('Building zlib') + zlib_dir = next(self.build_libs_dir.glob('zlib-*')) + subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(zlib_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(zlib_dir), env=env) + + def _build_libiconv(self, env, prefix_arg, host_arg): + self.info('Building libiconv') + libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + *host_arg, + ], + cwd=str(libiconv_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libiconv_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libiconv_dir), env=env) + + def _build_libxml2(self, env, prefix_arg, host_arg): + self.info('Building LibXML2') + libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + '--without-lzma', + '--without-python', + f'--with-iconv={self.prefix_dir}', + f'--with-zlib={self.prefix_dir}', + *host_arg, + ], + cwd=str(libxml2_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxml2_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxml2_dir), env=env) + + def _build_libxslt(self, env, prefix_arg, host_arg): + self.info('Building libxslt') + libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-dependency-tracking', + '--disable-shared', + '--without-python', + '--without-crypto', + f'--with-libxml-prefix={self.prefix_dir}', + *host_arg, + ], + cwd=str(libxslt_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxslt_dir), env=env) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxslt_dir), env=env) + + def _build_xmlsec1(self, env, prefix_arg, host_arg): + self.info('Building xmlsec1') + xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) + subprocess.check_call( + [ + './configure', + prefix_arg, + '--disable-shared', + '--disable-gost', + '--enable-md5', + '--enable-ripemd160', + '--disable-crypto-dl', + '--enable-static=yes', + '--enable-shared=no', + '--enable-static-linking=yes', + '--with-default-crypto=openssl', + f'--with-openssl={self.prefix_dir}', + f'--with-libxml={self.prefix_dir}', + f'--with-libxslt={self.prefix_dir}', + *host_arg, + ], + cwd=str(xmlsec1_dir), + env=env, + ) + include_flags = [ + f'-I{self.prefix_dir / "include"}', + f'-I{self.prefix_dir / "include" / "libxml"}', + ] + subprocess.check_call( + ['make', f'-j{multiprocessing.cpu_count() + 1}', *include_flags], + cwd=str(xmlsec1_dir), + env=env, + ) + subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(xmlsec1_dir), env=env) + + +__all__ = ('CrossCompileInfo', 'LibXmlsecDependencyBuilder') diff --git a/build_support/static_build.py b/build_support/static_build.py index 09e2039a..34d06ae6 100644 --- a/build_support/static_build.py +++ b/build_support/static_build.py @@ -1,35 +1,7 @@ -import multiprocessing -import os -import platform -import subprocess import sys -import tarfile -import zipfile from distutils.errors import DistutilsError -from pathlib import Path -from urllib.parse import urljoin -from urllib.request import urlcleanup -from .network import download_lib -from .releases import ( - latest_libiconv_release, - latest_libxml2_release, - latest_libxslt_release, - latest_openssl_release, - latest_xmlsec_release, - latest_zlib_release, -) - - -class CrossCompileInfo: - def __init__(self, host, arch, compiler): - self.host = host - self.arch = arch - self.compiler = compiler - - @property - def triplet(self): - return f'{self.host}-{self.arch}-{self.compiler}' +from .lib_xmlsec_dependency_builder import CrossCompileInfo, LibXmlsecDependencyBuilder class StaticBuildHelper: @@ -37,70 +9,35 @@ def __init__(self, builder): self.builder = builder self.ext = builder.ext_map['xmlsec'] self.info = builder.info - self._prepare_directories() def prepare(self, platform_name): self.info(f'starting static build on {sys.platform}') - if platform_name == 'win32': - self._prepare_windows_build() - elif 'linux' in platform_name or 'darwin' in platform_name: - self._prepare_unix_build(platform_name) - else: - raise DistutilsError(f'Unsupported static build platform: {platform_name}') - - def _prepare_directories(self): - buildroot = Path('build', 'tmp') - - prefix_dir = buildroot / 'prefix' - prefix_dir.mkdir(parents=True, exist_ok=True) - self.prefix_dir = prefix_dir.absolute() - - build_libs_dir = buildroot / 'libs' - build_libs_dir.mkdir(exist_ok=True) - self.build_libs_dir = build_libs_dir + deps_builder = LibXmlsecDependencyBuilder( + platform_name=platform_name, + info=self.info, + plat_name=getattr(self.builder, 'plat_name', None), + ) + deps_builder.prepare() - libs_dir = Path(os.environ.get('PYXMLSEC_LIBS_DIR', 'libs')) - libs_dir.mkdir(exist_ok=True) - self.libs_dir = libs_dir - self.info('{:20} {}'.format('Lib sources in:', self.libs_dir.absolute())) + self.prefix_dir = deps_builder.prefix_dir + self.build_libs_dir = deps_builder.build_libs_dir + self.libs_dir = deps_builder.libs_dir self.builder.prefix_dir = self.prefix_dir self.builder.build_libs_dir = self.build_libs_dir self.builder.libs_dir = self.libs_dir - def _prepare_windows_build(self): - release_url = 'https://github.com/mxamin/python-xmlsec-win-binaries/releases/download/2025.07.10/' - if platform.machine() == 'ARM64': - suffix = 'win-arm64' - elif sys.maxsize > 2**32: - suffix = 'win64' - else: - suffix = 'win32' + for version_attr, value in deps_builder.versions.items(): + setattr(self.builder, version_attr, value) - libs = [ - f'libxml2-2.11.9-3.{suffix}.zip', - f'libxslt-1.1.39.{suffix}.zip', - f'zlib-1.3.1.{suffix}.zip', - f'iconv-1.18-1.{suffix}.zip', - f'openssl-3.0.16.pl1.{suffix}.zip', - f'xmlsec-1.3.7.{suffix}.zip', - ] - - for libfile in libs: - url = urljoin(release_url, libfile) - destfile = self.libs_dir / libfile - if destfile.is_file(): - self.info(f'Using local copy of "{url}"') - else: - self.info(f'Retrieving "{url}" to "{destfile}"') - urlcleanup() - download_lib(url, str(destfile)) - - for package in self.libs_dir.glob('*.zip'): - with zipfile.ZipFile(str(package)) as archive: - destdir = self.build_libs_dir - archive.extractall(path=str(destdir)) + if platform_name == 'win32': + self._configure_windows_extension_for_static() + elif 'linux' in platform_name or 'darwin' in platform_name: + self._configure_unix_extension_for_static(platform_name) + else: + raise DistutilsError(f'Unsupported static build platform: {platform_name}') + def _configure_windows_extension_for_static(self): self.ext.define_macros = [ ('XMLSEC_CRYPTO', '\\"openssl\\"'), ('__XMLSEC_FUNCTION__', '__FUNCTION__'), @@ -137,282 +74,7 @@ def _prepare_windows_build(self): includes.append(next(path / 'xmlsec' for path in includes if (path / 'xmlsec').is_dir())) self.ext.include_dirs = [str(path.absolute()) for path in includes] - def _prepare_unix_build(self, build_platform): - self._capture_version_overrides() - archives = self._ensure_source_archives() - self._extract_archives(archives) - - env, prefix_arg, ldflags, cross_compile = self._prepare_build_environment(build_platform) - self._build_dependencies(env, prefix_arg, ldflags, cross_compile) - self._configure_extension_for_static(build_platform) - - def _capture_version_overrides(self): - builder = self.builder - builder.openssl_version = os.environ.get('PYXMLSEC_OPENSSL_VERSION', '3.6.0') - builder.libiconv_version = os.environ.get('PYXMLSEC_LIBICONV_VERSION', '1.18') - builder.libxml2_version = os.environ.get('PYXMLSEC_LIBXML2_VERSION', '2.14.6') - builder.libxslt_version = os.environ.get('PYXMLSEC_LIBXSLT_VERSION', '1.1.43') - builder.zlib_version = os.environ.get('PYXMLSEC_ZLIB_VERSION', '1.3.1') - builder.xmlsec1_version = os.environ.get('PYXMLSEC_XMLSEC1_VERSION', '1.3.9') - - def _ensure_source_archives(self): - return [ - self._ensure_source( - name='OpenSSL', - glob='openssl*.tar.gz', - filename='openssl.tar.gz', - version=self.builder.openssl_version, - env_label='PYXMLSEC_OPENSSL_VERSION', - default_url=latest_openssl_release, - version_url=lambda v: f'https://api.github.com/repos/openssl/openssl/tarball/openssl-{v}', - ), - self._ensure_source( - name='zlib', - glob='zlib*.tar.gz', - filename='zlib.tar.gz', - version=self.builder.zlib_version, - env_label='PYXMLSEC_ZLIB_VERSION', - default_url=latest_zlib_release, - version_url=lambda v: f'https://zlib.net/fossils/zlib-{v}.tar.gz', - ), - self._ensure_source( - name='libiconv', - glob='libiconv*.tar.gz', - filename='libiconv.tar.gz', - version=self.builder.libiconv_version, - env_label='PYXMLSEC_LIBICONV_VERSION', - default_url=latest_libiconv_release, - version_url=lambda v: f'https://ftpmirror.gnu.org/libiconv/libiconv-{v}.tar.gz', - ), - self._ensure_source( - name='libxml2', - glob='libxml2*.tar.xz', - filename='libxml2.tar.xz', - version=self.builder.libxml2_version, - env_label='PYXMLSEC_LIBXML2_VERSION', - default_url=latest_libxml2_release, - version_url=lambda v: self._libxml_related_url('libxml2', v), - ), - self._ensure_source( - name='libxslt', - glob='libxslt*.tar.xz', - filename='libxslt.tar.xz', - version=self.builder.libxslt_version, - env_label='PYXMLSEC_LIBXSLT_VERSION', - default_url=latest_libxslt_release, - version_url=lambda v: self._libxml_related_url('libxslt', v), - ), - self._ensure_source( - name='xmlsec1', - glob='xmlsec1*.tar.gz', - filename='xmlsec1.tar.gz', - version=self.builder.xmlsec1_version, - env_label='PYXMLSEC_XMLSEC1_VERSION', - default_url=latest_xmlsec_release, - version_url=lambda v: f'https://github.com/lsh123/xmlsec/releases/download/{v}/xmlsec1-{v}.tar.gz', - ), - ] - - def _ensure_source(self, name, glob, filename, version, env_label, default_url, version_url): - archive = next(self.libs_dir.glob(glob), None) - if archive is not None: - return archive - - self.info('{:10}: {}'.format(name, 'source tar not found, downloading ...')) - archive = self.libs_dir / filename - if version is None: - url = default_url() - self.info('{:10}: {}'.format(name, f'{env_label} unset, downloading latest from {url}')) - else: - url = version_url(version) - self.info('{:10}: {}'.format(name, f'{env_label}={version}, downloading from {url}')) - download_lib(url, str(archive)) - return archive - - def _libxml_related_url(self, lib_name, version): - version_prefix, _ = version.rsplit('.', 1) - return f'https://download.gnome.org/sources/{lib_name}/{version_prefix}/{lib_name}-{version}.tar.xz' - - def _extract_archives(self, archives): - for archive in archives: - self.info(f'Unpacking {archive.name}') - try: - with tarfile.open(str(archive)) as tar: - tar.extractall(path=str(self.build_libs_dir)) - except EOFError as error: - raise DistutilsError(f'Bad {archive.name} downloaded; remove it and try again.') from error - - def _prepare_build_environment(self, build_platform): - prefix_arg = f'--prefix={self.prefix_dir}' - env = os.environ.copy() - - cflags = [] - if env.get('CFLAGS'): - cflags.append(env['CFLAGS']) - cflags.append('-fPIC') - - ldflags = [] - if env.get('LDFLAGS'): - ldflags.append(env['LDFLAGS']) - - cross_compile = None - if build_platform == 'darwin': - arch = self.builder.plat_name.rsplit('-', 1)[1] - if arch != platform.machine() and arch in ('x86_64', 'arm64'): - self.info(f'Cross-compiling for {arch}') - cflags.append(f'-arch {arch}') - ldflags.append(f'-arch {arch}') - cross_compile = CrossCompileInfo('darwin64', arch, 'cc') - major_version, _ = tuple(map(int, platform.mac_ver()[0].split('.')[:2])) - if major_version >= 11 and 'MACOSX_DEPLOYMENT_TARGET' not in env: - env['MACOSX_DEPLOYMENT_TARGET'] = '11.0' - - env['CFLAGS'] = ' '.join(cflags) - env['LDFLAGS'] = ' '.join(ldflags) - return env, prefix_arg, ldflags, cross_compile - - def _build_dependencies(self, env, prefix_arg, ldflags, cross_compile): - self._build_openssl(env, prefix_arg, cross_compile) - self._build_zlib(env, prefix_arg) - - host_arg = [f'--host={cross_compile.arch}'] if cross_compile else [] - self._build_libiconv(env, prefix_arg, host_arg) - self._build_libxml2(env, prefix_arg, host_arg) - self._build_libxslt(env, prefix_arg, host_arg) - - ldflags.append('-lpthread') - env['LDFLAGS'] = ' '.join(ldflags) - self._build_xmlsec1(env, prefix_arg, host_arg) - - def _build_openssl(self, env, prefix_arg, cross_compile): - self.info('Building OpenSSL') - openssl_dir = next(self.build_libs_dir.glob('openssl-*')) - openssl_config_cmd = [prefix_arg, 'no-shared', '-fPIC', '--libdir=lib'] - if platform.machine() == 'riscv64': - # openssl(riscv64): disable ASM to avoid R_RISCV_JAL relocation failure on 3.5.2 - # OpenSSL 3.5.2 enables RISC-V64 AES assembly by default. When we statically - # link libcrypto alongside xmlsec, the AES asm path triggers a link-time error: - # relocation truncated to fit: R_RISCV_JAL against symbol `AES_set_encrypt_key' - # in .../libcrypto.a(libcrypto-lib-aes-riscv64.o) - # This appears to stem from a long-range jump emitted by the AES asm generator - # (see aes-riscv64.pl around L1069), which can exceed the JAL reach when objects - # end up far apart in the final static link. - # As a pragmatic workaround, disable ASM on riscv64 (pass `no-asm`) so the - # portable C implementation is used. This unblocks the build at the cost of - # some crypto performance on riscv64 only. - # Refs: - # - https://github.com/openssl/openssl/blob/0893a62/crypto/aes/asm/aes-riscv64.pl#L1069 - openssl_config_cmd.append('no-asm') - if cross_compile: - openssl_config_cmd.insert(0, './Configure') - openssl_config_cmd.append(cross_compile.triplet) - else: - openssl_config_cmd.insert(0, './config') - subprocess.check_call(openssl_config_cmd, cwd=str(openssl_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(openssl_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install_sw'], cwd=str(openssl_dir), env=env) - - def _build_zlib(self, env, prefix_arg): - self.info('Building zlib') - zlib_dir = next(self.build_libs_dir.glob('zlib-*')) - subprocess.check_call(['./configure', prefix_arg], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(zlib_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(zlib_dir), env=env) - - def _build_libiconv(self, env, prefix_arg, host_arg): - self.info('Building libiconv') - libiconv_dir = next(self.build_libs_dir.glob('libiconv-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - *host_arg, - ], - cwd=str(libiconv_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libiconv_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libiconv_dir), env=env) - - def _build_libxml2(self, env, prefix_arg, host_arg): - self.info('Building LibXML2') - libxml2_dir = next(self.build_libs_dir.glob('libxml2-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - '--without-lzma', - '--without-python', - f'--with-iconv={self.prefix_dir}', - f'--with-zlib={self.prefix_dir}', - *host_arg, - ], - cwd=str(libxml2_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxml2_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxml2_dir), env=env) - - def _build_libxslt(self, env, prefix_arg, host_arg): - self.info('Building libxslt') - libxslt_dir = next(self.build_libs_dir.glob('libxslt-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-dependency-tracking', - '--disable-shared', - '--without-python', - '--without-crypto', - f'--with-libxml-prefix={self.prefix_dir}', - *host_arg, - ], - cwd=str(libxslt_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}'], cwd=str(libxslt_dir), env=env) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(libxslt_dir), env=env) - - def _build_xmlsec1(self, env, prefix_arg, host_arg): - self.info('Building xmlsec1') - xmlsec1_dir = next(self.build_libs_dir.glob('xmlsec1-*')) - subprocess.check_call( - [ - './configure', - prefix_arg, - '--disable-shared', - '--disable-gost', - '--enable-md5', - '--enable-ripemd160', - '--disable-crypto-dl', - '--enable-static=yes', - '--enable-shared=no', - '--enable-static-linking=yes', - '--with-default-crypto=openssl', - f'--with-openssl={self.prefix_dir}', - f'--with-libxml={self.prefix_dir}', - f'--with-libxslt={self.prefix_dir}', - *host_arg, - ], - cwd=str(xmlsec1_dir), - env=env, - ) - include_flags = [ - f'-I{self.prefix_dir / "include"}', - f'-I{self.prefix_dir / "include" / "libxml"}', - ] - subprocess.check_call( - ['make', f'-j{multiprocessing.cpu_count() + 1}', *include_flags], - cwd=str(xmlsec1_dir), - env=env, - ) - subprocess.check_call(['make', f'-j{multiprocessing.cpu_count() + 1}', 'install'], cwd=str(xmlsec1_dir), env=env) - - def _configure_extension_for_static(self, build_platform): + def _configure_unix_extension_for_static(self, build_platform): self.ext.define_macros = [ ('__XMLSEC_FUNCTION__', '__func__'), ('XMLSEC_NO_SIZE_T', None), diff --git a/pyproject.toml b/pyproject.toml index 7c7b4bf3..89ace626 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,56 @@ [build-system] -requires = ["setuptools==80.9.0", "wheel", "setuptools_scm[toml]>=3.4", "pkgconfig>=1.5.1", "lxml==6.0.2"] +requires = ["setuptools", "wheel", "setuptools_scm>=8", "pkgconfig>=1.5.1", "lxml>=3.8"] +[project] +name = "xmlsec" +dynamic = ["version"] +description = "Python bindings for the XML Security Library" +readme = {file = "README.md", content-type = "text/markdown"} +requires-python = ">=3.9" +dependencies = ["lxml>=3.8"] +keywords = ["xmlsec"] +authors = [ + {name = "Bulat Gaifullin", email = "support@mehcode.com"} +] +maintainers = [ + {name = "Oleg Hoefling", email = "oleg.hoefling@gmail.com"}, + {name = "Amin Solhizadeh", email = "amin.solhizadeh@gmail.com"} +] +license = "MIT" +classifiers = [ + "Development Status :: 5 - Production/Stable", + "Intended Audience :: Developers", + "Intended Audience :: System Administrators", + "Operating System :: OS Independent", + "Programming Language :: C", + "Programming Language :: Python :: 3", + "Programming Language :: Python :: 3.9", + "Programming Language :: Python :: 3.10", + "Programming Language :: Python :: 3.11", + "Programming Language :: Python :: 3.12", + "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", + "Topic :: Text Processing :: Markup :: XML", + "Typing :: Typed" +] + +[project.urls] +Documentation = "https://xmlsec.readthedocs.io" +Source = "https://github.com/xmlsec/python-xmlsec" +Changelog = "https://github.com/xmlsec/python-xmlsec/releases" + +# setuptools +[tool.setuptools] +zip-safe = false +packages = ["xmlsec"] +package-dir = {"" = "src"} + +[tool.setuptools.package-data] +xmlsec = ["py.typed", "*.pyi"] + +[tool.setuptools_scm] + +# mypy [tool.mypy] files = ['src'] ignore_missing_imports = false @@ -22,6 +72,19 @@ warn_no_return = true no_implicit_reexport = true show_error_codes = true +# TODO: Remove this override after adding full type annotations in build tooling modules. +[[tool.mypy.overrides]] +module = [ + "build_support.network", + "build_support.releases", + "build_support.lib_xmlsec_dependency_builder", + "build_libs_xmlsec" +] +disallow_untyped_calls = false +disallow_untyped_defs = false +disable_error_code = ["attr-defined"] + +# ruff [tool.ruff] # Maximum line length, same as your original Black + Flake8 config line-length = 130 @@ -88,6 +151,7 @@ skip-magic-trailing-comma = false # Enforce Unix-style line endings (LF) line-ending = "lf" +# cibuildwheel [tool.cibuildwheel] build = [ "cp39-*", @@ -98,6 +162,7 @@ build = [ "cp314-*" ] build-verbosity = 1 +environment = {PYXMLSEC_STATIC_DEPS="true"} build-frontend = "build" skip = [ "pp*", # Skips PyPy builds (pp38-*, pp39-*, etc.) @@ -105,23 +170,16 @@ skip = [ ] test-command = "pytest -v --color=yes {package}/tests" before-test = "pip install -r requirements-test.txt" -test-skip = "*-macosx_arm64" - -[tool.cibuildwheel.environment] -PYXMLSEC_STATIC_DEPS = "true" [tool.cibuildwheel.linux] archs = ["x86_64", "aarch64", "riscv64"] environment-pass = [ - "PYXMLSEC_LIBXML2_VERSION", - "PYXMLSEC_LIBXSLT_VERSION", "PYXMLSEC_STATIC_DEPS", "GH_TOKEN" ] [tool.cibuildwheel.macos] archs = ["x86_64", "arm64"] -before-all = "brew install perl" [tool.cibuildwheel.windows] archs = ["AMD64"] diff --git a/requirements-test.txt b/requirements-test.txt index ad135d97..70fe9703 100644 --- a/requirements-test.txt +++ b/requirements-test.txt @@ -2,4 +2,4 @@ pytest==8.4.1 lxml-stubs==0.5.1 -ruff[format]==0.13.0 +ruff[format]==0.14.4 diff --git a/setup.cfg b/setup.cfg deleted file mode 100644 index 8762c654..00000000 --- a/setup.cfg +++ /dev/null @@ -1,22 +0,0 @@ -[metadata] -description_file = README.md - -[bdist_rpm] -release = 1 -build_requires = pkg-config xmlsec1-devel libxml2-devel xmlsec1-openssl-devel -group = Development/Libraries -requires = xmlsec1 xmlsec1-openssl - -[build_sphinx] -source-dir = doc/source -build-dir = doc/build -all_files = 1 - -# [flake8] -# per-file-ignores = -# *.pyi: E301, E302, E305, E501, E701, F401, F822 -# doc/source/conf.py: D1 -# doc/source/examples/*.py: D1, E501 -# tests/*.py: D1 -# exclude = .venv*,.git,*_pb2.pyi,build,dist,libs,.eggs,.direnv* -# max-line-length = 130 diff --git a/setup.py b/setup.py index 4100a52b..946855f1 100644 --- a/setup.py +++ b/setup.py @@ -5,57 +5,11 @@ from build_support.build_ext import build_ext src_root = Path(__file__).parent / 'src' -sources = [str(path.absolute()) for path in src_root.rglob('*.c')] +sources = [str(path.relative_to(Path(__file__).parent)) for path in src_root.rglob('*.c')] pyxmlsec = Extension('xmlsec', sources=sources) -setup_reqs = ['setuptools_scm[toml]>=3.4', 'pkgconfig>=1.5.1', 'lxml>=3.8'] - - -with open('README.md', encoding='utf-8') as readme: - long_desc = readme.read() setup( - name='xmlsec', - use_scm_version=True, - description='Python bindings for the XML Security Library', - long_description=long_desc, - long_description_content_type='text/markdown', ext_modules=[pyxmlsec], cmdclass={'build_ext': build_ext}, - python_requires='>=3.9', - setup_requires=setup_reqs, - install_requires=['lxml>=3.8'], - author='Bulat Gaifullin', - author_email='support@mehcode.com', - maintainer='Oleg Hoefling', - maintainer_email='oleg.hoefling@gmail.com', - url='https://github.com/mehcode/python-xmlsec', - project_urls={ - 'Documentation': 'https://xmlsec.readthedocs.io', - 'Source': 'https://github.com/mehcode/python-xmlsec', - 'Changelog': 'https://github.com/mehcode/python-xmlsec/releases', - }, - license='MIT', - keywords=['xmlsec'], - classifiers=[ - 'Development Status :: 5 - Production/Stable', - 'Intended Audience :: Developers', - 'Intended Audience :: System Administrators', - 'License :: OSI Approved :: MIT License', - 'Operating System :: OS Independent', - 'Programming Language :: C', - 'Programming Language :: Python :: 3', - 'Programming Language :: Python :: 3.9', - 'Programming Language :: Python :: 3.10', - 'Programming Language :: Python :: 3.11', - 'Programming Language :: Python :: 3.12', - 'Programming Language :: Python :: 3.13', - 'Programming Language :: Python :: 3.14', - 'Topic :: Text Processing :: Markup :: XML', - 'Typing :: Typed', - ], - zip_safe=False, - packages=['xmlsec'], - package_dir={'': 'src'}, - package_data={'xmlsec': ['py.typed', '*.pyi']}, )