nemtus-symbol-lightapi 0.0.9__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- nemtus_symbol_lightapi-0.0.9/PKG-INFO +28 -0
- nemtus_symbol_lightapi-0.0.9/README.md +7 -0
- nemtus_symbol_lightapi-0.0.9/cffi_src/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/cffi_src/openssl_build.py +125 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/PKG-INFO +28 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/SOURCES.txt +51 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/dependency_links.txt +1 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/not-zip-safe +1 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/requires.txt +4 -0
- nemtus_symbol_lightapi-0.0.9/nemtus_symbol_lightapi.egg-info/top_level.txt +4 -0
- nemtus_symbol_lightapi-0.0.9/pyproject.toml +12 -0
- nemtus_symbol_lightapi-0.0.9/setup.cfg +33 -0
- nemtus_symbol_lightapi-0.0.9/setup.py +34 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/bindings/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/bindings/openssl.py +7 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/BasicConnector.py +62 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/CatapultCertificateProcessor.py +76 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/CertificateUtils.py +66 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/ConnectorExtensions.py +65 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/NemBlockCalculator.py +274 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/NemConnector.py +429 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/SymbolConnector.py +339 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/SymbolPeerConnector.py +170 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/connector/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/Block.py +32 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/Constants.py +13 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/Endpoint.py +21 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/Exceptions.py +28 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/NodeInfo.py +66 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/PacketHeader.py +62 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/Transaction.py +564 -0
- nemtus_symbol_lightapi-0.0.9/symbollightapi/model/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/tests/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_BasicConnector.py +407 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_CatapultCertificateProcessor.py +286 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_CertificateUtils.py +168 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_ConnectorExtensions.py +236 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_NemBlockCalculator.py +279 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_NemConnector.py +1445 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_SymbolConnector.py +927 -0
- nemtus_symbol_lightapi-0.0.9/tests/connector/test_SymbolPeerConnector.py +294 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/__init__.py +0 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/test_Block.py +70 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/test_Endpoint.py +57 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/test_NodeInfo.py +177 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/test_PacketHeader.py +43 -0
- nemtus_symbol_lightapi-0.0.9/tests/model/test_Transaction.py +401 -0
- nemtus_symbol_lightapi-0.0.9/tests/test/CertificateTestUtils.py +114 -0
- nemtus_symbol_lightapi-0.0.9/tests/test/LightApiTestUtils.py +24 -0
- nemtus_symbol_lightapi-0.0.9/tests/test/__init__.py +0 -0
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nemtus-symbol-lightapi
|
|
3
|
+
Version: 0.0.9
|
|
4
|
+
Summary: Symbol Light API (NEMTUS mirror of upstream symbol-lightapi; import module: symbollightapi)
|
|
5
|
+
Home-page: https://github.com/nemtus/symbol-product/tree/dev/lightapi/python
|
|
6
|
+
Author: NEMTUS
|
|
7
|
+
Author-email: info@nemtus.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: symbol,symbollightapi,lightapi,Symbol Light API,nemtus
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: aiohttp~=3.14.0
|
|
18
|
+
Requires-Dist: aiolimiter~=1.2.1
|
|
19
|
+
Requires-Dist: nemtus-symbol-sdk~=3.3.2
|
|
20
|
+
Requires-Dist: zenlog~=1.1
|
|
21
|
+
|
|
22
|
+
# Python Light API
|
|
23
|
+
|
|
24
|
+
Provides partial Python wrappers for calling NEM and Symbol API functions.
|
|
25
|
+
|
|
26
|
+
Only a subset of APIs are currently supported.
|
|
27
|
+
|
|
28
|
+
PRs are accepted for extending the set of APIs.
|
|
File without changes
|
|
@@ -0,0 +1,125 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from pathlib import Path
|
|
3
|
+
|
|
4
|
+
from cffi import FFI
|
|
5
|
+
|
|
6
|
+
ffi_builder = FFI()
|
|
7
|
+
|
|
8
|
+
# if specified, add openssl to the include path
|
|
9
|
+
include_dirs = []
|
|
10
|
+
library_dirs = []
|
|
11
|
+
openssl_root_dir = os.environ.get('OPENSSL_ROOT_DIR', None)
|
|
12
|
+
if openssl_root_dir:
|
|
13
|
+
include_dirs += [Path(openssl_root_dir) / 'include']
|
|
14
|
+
library_dirs += [str(Path(openssl_root_dir) / 'lib')]
|
|
15
|
+
|
|
16
|
+
# build '_openssl_symbol' module and include openssl headers
|
|
17
|
+
ffi_builder.set_source(
|
|
18
|
+
'_openssl_symbol',
|
|
19
|
+
r'''
|
|
20
|
+
#include <openssl/ssl.h>
|
|
21
|
+
typedef STACK_OF(X509) Cryptography_STACK_OF_X509; // replacement for STACK_OF(X509)
|
|
22
|
+
''',
|
|
23
|
+
include_dirs=include_dirs,
|
|
24
|
+
library_dirs=library_dirs,
|
|
25
|
+
libraries=['libcrypto', 'libssl'] if os.name == 'nt' else ['crypto', 'ssl'])
|
|
26
|
+
|
|
27
|
+
# add all openssl constants, types and functions being used
|
|
28
|
+
ffi_builder.cdef('''
|
|
29
|
+
// constants
|
|
30
|
+
static const int MBSTRING_ASC;
|
|
31
|
+
static const int XN_FLAG_RFC2253;
|
|
32
|
+
|
|
33
|
+
static const int SSL_VERIFY_PEER;
|
|
34
|
+
static const int SSL_VERIFY_FAIL_IF_NO_PEER_CERT;
|
|
35
|
+
|
|
36
|
+
static const int EVP_PKEY_ED25519;
|
|
37
|
+
static const int EVP_PKEY_X25519;
|
|
38
|
+
|
|
39
|
+
static const int X509_V_ERR_APPLICATION_VERIFICATION;
|
|
40
|
+
static const int X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN;
|
|
41
|
+
|
|
42
|
+
static const int X509_V_FLAG_CHECK_SS_SIGNATURE;
|
|
43
|
+
|
|
44
|
+
// types
|
|
45
|
+
typedef ... SSL_CTX;
|
|
46
|
+
typedef ... BIO;
|
|
47
|
+
typedef ... BIO_METHOD;
|
|
48
|
+
typedef ... ENGINE;
|
|
49
|
+
typedef ... EVP_MD;
|
|
50
|
+
typedef ... EVP_PKEY;
|
|
51
|
+
typedef ... X509;
|
|
52
|
+
typedef ... Cryptography_STACK_OF_X509;
|
|
53
|
+
typedef ... X509_STORE;
|
|
54
|
+
typedef ... X509_STORE_CTX;
|
|
55
|
+
typedef ... X509_NAME;
|
|
56
|
+
typedef ... ASN1_INTEGER;
|
|
57
|
+
typedef ... ASN1_TIME;
|
|
58
|
+
|
|
59
|
+
// SSL_CTX
|
|
60
|
+
void SSL_CTX_set_verify(SSL_CTX *ctx, int mode, int (*verify_callback)(int, X509_STORE_CTX *));
|
|
61
|
+
|
|
62
|
+
// BIO_METHOD
|
|
63
|
+
const BIO_METHOD * BIO_s_mem(void);
|
|
64
|
+
|
|
65
|
+
// BIO
|
|
66
|
+
BIO* BIO_new(const BIO_METHOD *type);
|
|
67
|
+
int BIO_free(BIO *a);
|
|
68
|
+
long BIO_get_mem_data(BIO *b, char **pp);
|
|
69
|
+
|
|
70
|
+
// EVP_PKEY
|
|
71
|
+
EVP_PKEY *EVP_PKEY_new_raw_private_key(int type, ENGINE *e, const unsigned char *key, size_t keylen);
|
|
72
|
+
void EVP_PKEY_free(EVP_PKEY *key);
|
|
73
|
+
int EVP_PKEY_id(const EVP_PKEY *pkey);
|
|
74
|
+
int EVP_PKEY_get_raw_public_key(const EVP_PKEY *pkey, unsigned char *pub, size_t *len);
|
|
75
|
+
|
|
76
|
+
// X509
|
|
77
|
+
X509 *X509_new(void);
|
|
78
|
+
void X509_free(X509 *a);
|
|
79
|
+
EVP_PKEY *X509_get0_pubkey(const X509 *x);
|
|
80
|
+
X509_NAME *X509_get_subject_name(const X509 *x);
|
|
81
|
+
X509_NAME *X509_get_issuer_name(const X509 *x);
|
|
82
|
+
ASN1_INTEGER *X509_get_serialNumber(X509 *x);
|
|
83
|
+
ASN1_TIME *X509_getm_notBefore(const X509 *x);
|
|
84
|
+
ASN1_TIME *X509_getm_notAfter(const X509 *x);
|
|
85
|
+
int X509_set_pubkey(X509 *x, EVP_PKEY *pkey);
|
|
86
|
+
int X509_set_version(X509 *x, long version);
|
|
87
|
+
int X509_sign(X509 *x, EVP_PKEY *pkey, const EVP_MD *md);
|
|
88
|
+
|
|
89
|
+
// STACK_OF(X509)
|
|
90
|
+
Cryptography_STACK_OF_X509 *sk_X509_new_null(void);
|
|
91
|
+
void sk_X509_free(Cryptography_STACK_OF_X509 *sk);
|
|
92
|
+
int sk_X509_num(const Cryptography_STACK_OF_X509 *sk);
|
|
93
|
+
int sk_X509_push(Cryptography_STACK_OF_X509 *sk, X509 *ptr);
|
|
94
|
+
|
|
95
|
+
// X509_STORE
|
|
96
|
+
X509_STORE *X509_STORE_new(void);
|
|
97
|
+
void X509_STORE_free(X509_STORE *v);
|
|
98
|
+
int X509_STORE_add_cert(X509_STORE *ctx, X509 *x);
|
|
99
|
+
|
|
100
|
+
// X509_STORE_CTX
|
|
101
|
+
X509_STORE_CTX *X509_STORE_CTX_new(void);
|
|
102
|
+
void X509_STORE_CTX_free(X509_STORE_CTX *ctx);
|
|
103
|
+
int X509_STORE_CTX_init(X509_STORE_CTX *ctx, X509_STORE *trust_store, X509 *target, Cryptography_STACK_OF_X509 *untrusted);
|
|
104
|
+
Cryptography_STACK_OF_X509 *X509_STORE_CTX_get0_chain(X509_STORE_CTX *ctx);
|
|
105
|
+
X509 *X509_STORE_CTX_get_current_cert(X509_STORE_CTX *ctx);
|
|
106
|
+
int X509_STORE_CTX_get_error(X509_STORE_CTX *ctx);
|
|
107
|
+
void X509_STORE_CTX_set_error(X509_STORE_CTX *ctx, int s);
|
|
108
|
+
void X509_STORE_CTX_set_current_cert(X509_STORE_CTX *ctx, X509 *x);
|
|
109
|
+
void X509_STORE_CTX_set0_verified_chain(X509_STORE_CTX *ctx, Cryptography_STACK_OF_X509 *chain);
|
|
110
|
+
void X509_STORE_CTX_set_flags(X509_STORE_CTX *ctx, unsigned long flags);
|
|
111
|
+
int X509_verify_cert(X509_STORE_CTX *ctx);
|
|
112
|
+
|
|
113
|
+
// X509_NAME
|
|
114
|
+
int X509_NAME_add_entry_by_txt(X509_NAME *name, const char *field, int type, const unsigned char *bytes, int len, int loc, int set);
|
|
115
|
+
int X509_NAME_print_ex(BIO *out, const X509_NAME *nm, int indent, unsigned long flags);
|
|
116
|
+
|
|
117
|
+
// ASN1_INTEGER
|
|
118
|
+
int ASN1_INTEGER_set(ASN1_INTEGER *a, long v);
|
|
119
|
+
|
|
120
|
+
// ASN1_TIME
|
|
121
|
+
ASN1_TIME *X509_gmtime_adj(ASN1_TIME *asn1_time, long offset_sec);
|
|
122
|
+
''')
|
|
123
|
+
|
|
124
|
+
if '__main__' == __name__:
|
|
125
|
+
ffi_builder.compile(verbose=True)
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: nemtus-symbol-lightapi
|
|
3
|
+
Version: 0.0.9
|
|
4
|
+
Summary: Symbol Light API (NEMTUS mirror of upstream symbol-lightapi; import module: symbollightapi)
|
|
5
|
+
Home-page: https://github.com/nemtus/symbol-product/tree/dev/lightapi/python
|
|
6
|
+
Author: NEMTUS
|
|
7
|
+
Author-email: info@nemtus.com
|
|
8
|
+
License: MIT
|
|
9
|
+
Keywords: symbol,symbollightapi,lightapi,Symbol Light API,nemtus
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Python: >=3.10
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
Requires-Dist: aiohttp~=3.14.0
|
|
18
|
+
Requires-Dist: aiolimiter~=1.2.1
|
|
19
|
+
Requires-Dist: nemtus-symbol-sdk~=3.3.2
|
|
20
|
+
Requires-Dist: zenlog~=1.1
|
|
21
|
+
|
|
22
|
+
# Python Light API
|
|
23
|
+
|
|
24
|
+
Provides partial Python wrappers for calling NEM and Symbol API functions.
|
|
25
|
+
|
|
26
|
+
Only a subset of APIs are currently supported.
|
|
27
|
+
|
|
28
|
+
PRs are accepted for extending the set of APIs.
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
README.md
|
|
2
|
+
pyproject.toml
|
|
3
|
+
setup.cfg
|
|
4
|
+
setup.py
|
|
5
|
+
cffi_src/__init__.py
|
|
6
|
+
cffi_src/openssl_build.py
|
|
7
|
+
nemtus_symbol_lightapi.egg-info/PKG-INFO
|
|
8
|
+
nemtus_symbol_lightapi.egg-info/SOURCES.txt
|
|
9
|
+
nemtus_symbol_lightapi.egg-info/dependency_links.txt
|
|
10
|
+
nemtus_symbol_lightapi.egg-info/not-zip-safe
|
|
11
|
+
nemtus_symbol_lightapi.egg-info/requires.txt
|
|
12
|
+
nemtus_symbol_lightapi.egg-info/top_level.txt
|
|
13
|
+
symbollightapi/__init__.py
|
|
14
|
+
symbollightapi/bindings/__init__.py
|
|
15
|
+
symbollightapi/bindings/openssl.py
|
|
16
|
+
symbollightapi/connector/BasicConnector.py
|
|
17
|
+
symbollightapi/connector/CatapultCertificateProcessor.py
|
|
18
|
+
symbollightapi/connector/CertificateUtils.py
|
|
19
|
+
symbollightapi/connector/ConnectorExtensions.py
|
|
20
|
+
symbollightapi/connector/NemBlockCalculator.py
|
|
21
|
+
symbollightapi/connector/NemConnector.py
|
|
22
|
+
symbollightapi/connector/SymbolConnector.py
|
|
23
|
+
symbollightapi/connector/SymbolPeerConnector.py
|
|
24
|
+
symbollightapi/connector/__init__.py
|
|
25
|
+
symbollightapi/model/Block.py
|
|
26
|
+
symbollightapi/model/Constants.py
|
|
27
|
+
symbollightapi/model/Endpoint.py
|
|
28
|
+
symbollightapi/model/Exceptions.py
|
|
29
|
+
symbollightapi/model/NodeInfo.py
|
|
30
|
+
symbollightapi/model/PacketHeader.py
|
|
31
|
+
symbollightapi/model/Transaction.py
|
|
32
|
+
symbollightapi/model/__init__.py
|
|
33
|
+
tests/__init__.py
|
|
34
|
+
tests/connector/__init__.py
|
|
35
|
+
tests/connector/test_BasicConnector.py
|
|
36
|
+
tests/connector/test_CatapultCertificateProcessor.py
|
|
37
|
+
tests/connector/test_CertificateUtils.py
|
|
38
|
+
tests/connector/test_ConnectorExtensions.py
|
|
39
|
+
tests/connector/test_NemBlockCalculator.py
|
|
40
|
+
tests/connector/test_NemConnector.py
|
|
41
|
+
tests/connector/test_SymbolConnector.py
|
|
42
|
+
tests/connector/test_SymbolPeerConnector.py
|
|
43
|
+
tests/model/__init__.py
|
|
44
|
+
tests/model/test_Block.py
|
|
45
|
+
tests/model/test_Endpoint.py
|
|
46
|
+
tests/model/test_NodeInfo.py
|
|
47
|
+
tests/model/test_PacketHeader.py
|
|
48
|
+
tests/model/test_Transaction.py
|
|
49
|
+
tests/test/CertificateTestUtils.py
|
|
50
|
+
tests/test/LightApiTestUtils.py
|
|
51
|
+
tests/test/__init__.py
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
[metadata]
|
|
2
|
+
name = nemtus-symbol-lightapi
|
|
3
|
+
version = 0.0.9
|
|
4
|
+
author = NEMTUS
|
|
5
|
+
author_email = info@nemtus.com
|
|
6
|
+
description = Symbol Light API (NEMTUS mirror of upstream symbol-lightapi; import module: symbollightapi)
|
|
7
|
+
long_description = file: README.md
|
|
8
|
+
long_description_content_type = text/markdown
|
|
9
|
+
keywords = symbol, symbollightapi, lightapi, Symbol Light API, nemtus
|
|
10
|
+
license = MIT
|
|
11
|
+
classifiers =
|
|
12
|
+
Programming Language :: Python :: 3.10
|
|
13
|
+
Programming Language :: Python :: 3.11
|
|
14
|
+
Programming Language :: Python :: 3.12
|
|
15
|
+
Programming Language :: Python :: 3.13
|
|
16
|
+
Programming Language :: Python :: 3.14
|
|
17
|
+
url = https://github.com/nemtus/symbol-product/tree/dev/lightapi/python
|
|
18
|
+
|
|
19
|
+
[options]
|
|
20
|
+
zip_safe = False
|
|
21
|
+
include_package_data = True
|
|
22
|
+
packages = find:
|
|
23
|
+
python_requires = >=3.10
|
|
24
|
+
install_requires =
|
|
25
|
+
aiohttp~=3.14.0
|
|
26
|
+
aiolimiter~=1.2.1
|
|
27
|
+
nemtus-symbol-sdk~=3.3.2
|
|
28
|
+
zenlog~=1.1
|
|
29
|
+
|
|
30
|
+
[egg_info]
|
|
31
|
+
tag_build =
|
|
32
|
+
tag_date = 0
|
|
33
|
+
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import platform
|
|
2
|
+
import sys
|
|
3
|
+
|
|
4
|
+
from setuptools import setup
|
|
5
|
+
|
|
6
|
+
cmdclass = {}
|
|
7
|
+
|
|
8
|
+
if 'CPython' == platform.python_implementation():
|
|
9
|
+
try:
|
|
10
|
+
import wheel.bdist_wheel
|
|
11
|
+
|
|
12
|
+
class BDistWheel(wheel.bdist_wheel.bdist_wheel):
|
|
13
|
+
def __init__(self, dist, **kw):
|
|
14
|
+
super().__init__(dist, **kw)
|
|
15
|
+
self.py_limited_api = None
|
|
16
|
+
|
|
17
|
+
def finalize_options(self):
|
|
18
|
+
self.py_limited_api = f'cp3{sys.version_info[1]}'
|
|
19
|
+
wheel.bdist_wheel.bdist_wheel.finalize_options(self)
|
|
20
|
+
|
|
21
|
+
cmdclass['bdist_wheel'] = BDistWheel
|
|
22
|
+
except ImportError:
|
|
23
|
+
pass
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
if '__main__' == __name__:
|
|
27
|
+
setup(
|
|
28
|
+
# Ensure limited API is set on CPython
|
|
29
|
+
cmdclass=cmdclass,
|
|
30
|
+
# CFFI
|
|
31
|
+
zip_safe=False,
|
|
32
|
+
ext_package='symbollightapi/bindings',
|
|
33
|
+
cffi_modules=['cffi_src/openssl_build.py:ffi_builder'],
|
|
34
|
+
)
|
|
File without changes
|
|
File without changes
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
import json
|
|
3
|
+
|
|
4
|
+
from aiohttp import ClientSession, ClientTimeout, client_exceptions
|
|
5
|
+
|
|
6
|
+
from ..model.Exceptions import HttpException, NodeException
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
class BasicConnector:
|
|
10
|
+
"""Async connector for interacting with a node."""
|
|
11
|
+
|
|
12
|
+
def __init__(self, endpoint):
|
|
13
|
+
"""Creates a connector around an endpoint."""
|
|
14
|
+
|
|
15
|
+
self.endpoint = endpoint
|
|
16
|
+
self.timeout_seconds = None
|
|
17
|
+
|
|
18
|
+
async def _dispatch(self, action, url_path, property_name, not_found_as_error, **kwargs):
|
|
19
|
+
try:
|
|
20
|
+
timeout = ClientTimeout(total=self.timeout_seconds)
|
|
21
|
+
async with ClientSession(timeout=timeout) as session:
|
|
22
|
+
async with getattr(session, action)(f'{self.endpoint}/{url_path}', **kwargs) as response:
|
|
23
|
+
try:
|
|
24
|
+
response_json = await response.json()
|
|
25
|
+
except (client_exceptions.ContentTypeError, json.decoder.JSONDecodeError) as ex:
|
|
26
|
+
raise NodeException from ex
|
|
27
|
+
|
|
28
|
+
if 400 <= response.status and (404 != response.status or not_found_as_error):
|
|
29
|
+
error_message = f'HTTP request failed with code {response.status}'
|
|
30
|
+
for key in ('code', 'message'):
|
|
31
|
+
if key in response_json:
|
|
32
|
+
error_message += f'\n{response_json[key]}'
|
|
33
|
+
|
|
34
|
+
raise HttpException(error_message, response.status)
|
|
35
|
+
|
|
36
|
+
return response_json if property_name is None else response_json[property_name]
|
|
37
|
+
except (asyncio.TimeoutError, client_exceptions.ClientConnectorError) as ex:
|
|
38
|
+
raise NodeException from ex
|
|
39
|
+
|
|
40
|
+
async def get(self, url_path, property_name=None, not_found_as_error=True):
|
|
41
|
+
"""
|
|
42
|
+
Initiates a GET to the specified path and returns the desired property.
|
|
43
|
+
Raises NodeException on connection or content failure.
|
|
44
|
+
"""
|
|
45
|
+
|
|
46
|
+
return await self._dispatch('get', url_path, property_name, not_found_as_error)
|
|
47
|
+
|
|
48
|
+
async def post(self, url_path, request_payload, property_name=None, not_found_as_error=True):
|
|
49
|
+
"""
|
|
50
|
+
Initiates a POST to the specified path and returns the desired property.
|
|
51
|
+
Raises NodeException on connection or content failure.
|
|
52
|
+
"""
|
|
53
|
+
|
|
54
|
+
return await self._dispatch('post', url_path, property_name, not_found_as_error, json=request_payload)
|
|
55
|
+
|
|
56
|
+
async def put(self, url_path, request_payload, property_name=None, not_found_as_error=True):
|
|
57
|
+
"""
|
|
58
|
+
Initiates a PUT to the specified path and returns the desired property.
|
|
59
|
+
Raises NodeException on connection or content failure.
|
|
60
|
+
"""
|
|
61
|
+
|
|
62
|
+
return await self._dispatch('put', url_path, property_name, not_found_as_error, json=request_payload)
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
from zenlog import log
|
|
2
|
+
|
|
3
|
+
from ..bindings.openssl import lib
|
|
4
|
+
from .CertificateUtils import try_parse_certificate, verify_self_signed
|
|
5
|
+
|
|
6
|
+
|
|
7
|
+
class CatapultCertificateProcessor:
|
|
8
|
+
"""Catapult-specific certificate processor."""
|
|
9
|
+
|
|
10
|
+
def __init__(self):
|
|
11
|
+
"""Creates a new certificate processor."""
|
|
12
|
+
|
|
13
|
+
self.certificate_infos = []
|
|
14
|
+
|
|
15
|
+
@property
|
|
16
|
+
def size(self):
|
|
17
|
+
"""Gets the number of certificates in the chain."""
|
|
18
|
+
|
|
19
|
+
return len(self.certificate_infos)
|
|
20
|
+
|
|
21
|
+
def certificate(self, depth):
|
|
22
|
+
"""
|
|
23
|
+
Gets the parsed certificate information at depth.
|
|
24
|
+
Depth is 0-based starting with the root certificate.
|
|
25
|
+
"""
|
|
26
|
+
|
|
27
|
+
return self.certificate_infos[depth]
|
|
28
|
+
|
|
29
|
+
def verify(self, preverified, certificate_store_context):
|
|
30
|
+
"""Verifies the current certificate in certificate_store_context given preverified result."""
|
|
31
|
+
|
|
32
|
+
# reject all certificate chains that are not composed of two certificates
|
|
33
|
+
chain = lib.X509_STORE_CTX_get0_chain(certificate_store_context)
|
|
34
|
+
chain_size = lib.sk_X509_num(chain)
|
|
35
|
+
if 2 != chain_size:
|
|
36
|
+
log.warning(f'rejecting certificate chain with size {chain_size}')
|
|
37
|
+
return False
|
|
38
|
+
|
|
39
|
+
certificate = lib.X509_STORE_CTX_get_current_cert(certificate_store_context)
|
|
40
|
+
if not certificate:
|
|
41
|
+
raise RuntimeError('rejecting certificate chain with no active certificate')
|
|
42
|
+
|
|
43
|
+
if preverified:
|
|
44
|
+
if self._push(certificate):
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
lib.X509_STORE_CTX_set_error(certificate_store_context, lib.X509_V_ERR_APPLICATION_VERIFICATION)
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
error_code = lib.X509_STORE_CTX_get_error(certificate_store_context)
|
|
51
|
+
return self.verify_unverified_root(certificate, error_code)
|
|
52
|
+
|
|
53
|
+
def verify_unverified_root(self, certificate, error_code):
|
|
54
|
+
if self.certificate_infos:
|
|
55
|
+
log.warning('rejecting certificate chain with unverified non-root certificate')
|
|
56
|
+
return False
|
|
57
|
+
|
|
58
|
+
# only verify self signed certificates
|
|
59
|
+
if lib.X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN != error_code:
|
|
60
|
+
log.warning(f'rejecting certificate chain with unverified unexpected error {error_code}')
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
if not verify_self_signed(certificate):
|
|
64
|
+
log.warning('rejecting certificate chain with improperly self-signed root certificate')
|
|
65
|
+
return False
|
|
66
|
+
|
|
67
|
+
return True
|
|
68
|
+
|
|
69
|
+
def _push(self, certificate):
|
|
70
|
+
certificate_info = try_parse_certificate(certificate)
|
|
71
|
+
if not certificate_info:
|
|
72
|
+
log.warning('rejecting certificate chain due to certificate parse failure')
|
|
73
|
+
return False
|
|
74
|
+
|
|
75
|
+
self.certificate_infos.append(certificate_info)
|
|
76
|
+
return True
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
from collections import namedtuple
|
|
2
|
+
|
|
3
|
+
from symbolchain.CryptoTypes import PublicKey
|
|
4
|
+
|
|
5
|
+
from symbollightapi.bindings.openssl import ffi, lib
|
|
6
|
+
|
|
7
|
+
CertificateInfo = namedtuple('CertificateInfo', ['subject', 'public_key'])
|
|
8
|
+
|
|
9
|
+
# region try_parse_certificate
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def _extract_one_line(name):
|
|
13
|
+
bio = ffi.gc(lib.BIO_new(lib.BIO_s_mem()), lib.BIO_free)
|
|
14
|
+
|
|
15
|
+
if -1 == lib.X509_NAME_print_ex(bio, name, 0, lib.XN_FLAG_RFC2253):
|
|
16
|
+
return None
|
|
17
|
+
|
|
18
|
+
raw_data = ffi.new('char **')
|
|
19
|
+
data_size = lib.BIO_get_mem_data(bio, raw_data)
|
|
20
|
+
data = ffi.buffer(raw_data[0], data_size)[:]
|
|
21
|
+
return data.decode('utf8')
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def try_parse_certificate(certificate):
|
|
25
|
+
"""Tries to extract information about certificate."""
|
|
26
|
+
|
|
27
|
+
subject_x509_name = lib.X509_get_subject_name(certificate)
|
|
28
|
+
subject = _extract_one_line(subject_x509_name)
|
|
29
|
+
|
|
30
|
+
certificate_public_key = lib.X509_get0_pubkey(certificate)
|
|
31
|
+
if not certificate_public_key:
|
|
32
|
+
return None
|
|
33
|
+
|
|
34
|
+
if lib.EVP_PKEY_ED25519 != lib.EVP_PKEY_id(ffi.cast('EVP_PKEY *', certificate_public_key)):
|
|
35
|
+
return None
|
|
36
|
+
|
|
37
|
+
public_key = PublicKey(bytes(PublicKey.SIZE))
|
|
38
|
+
key_size_pointer = ffi.new('size_t *', PublicKey.SIZE)
|
|
39
|
+
if not lib.EVP_PKEY_get_raw_public_key(certificate_public_key, public_key.bytes, key_size_pointer):
|
|
40
|
+
return None
|
|
41
|
+
|
|
42
|
+
if PublicKey.SIZE != key_size_pointer[0]:
|
|
43
|
+
return None
|
|
44
|
+
|
|
45
|
+
return CertificateInfo(subject, public_key)
|
|
46
|
+
|
|
47
|
+
# endregion
|
|
48
|
+
|
|
49
|
+
|
|
50
|
+
# region verify_self_signed
|
|
51
|
+
|
|
52
|
+
def verify_self_signed(certificate):
|
|
53
|
+
"""Returns True if self-signed certificate signature is correct."""
|
|
54
|
+
|
|
55
|
+
certificate_store = ffi.gc(lib.X509_STORE_new(), lib.X509_STORE_free)
|
|
56
|
+
if not lib.X509_STORE_add_cert(certificate_store, certificate):
|
|
57
|
+
return False
|
|
58
|
+
|
|
59
|
+
certificate_store_context = ffi.gc(lib.X509_STORE_CTX_new(), lib.X509_STORE_CTX_free)
|
|
60
|
+
if not lib.X509_STORE_CTX_init(certificate_store_context, certificate_store, certificate, ffi.cast('Cryptography_STACK_OF_X509 *', 0)):
|
|
61
|
+
return False
|
|
62
|
+
|
|
63
|
+
lib.X509_STORE_CTX_set_flags(certificate_store_context, lib.X509_V_FLAG_CHECK_SS_SIGNATURE)
|
|
64
|
+
return 1 == lib.X509_verify_cert(certificate_store_context)
|
|
65
|
+
|
|
66
|
+
# endregion
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
import asyncio
|
|
2
|
+
|
|
3
|
+
from aiolimiter import AsyncLimiter
|
|
4
|
+
|
|
5
|
+
from ..model.Constants import DEFAULT_ASYNC_LIMITER_ARGUMENTS
|
|
6
|
+
|
|
7
|
+
# region get_incoming_transactions_from
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
async def get_incoming_transactions_from(connector, address, start_height=None, end_height=None):
|
|
11
|
+
"""Uses the specified connector to retrieve all transactions sent to an account in the range [start_height, end_height)."""
|
|
12
|
+
|
|
13
|
+
start_id = None
|
|
14
|
+
while True:
|
|
15
|
+
transactions_json = await connector.incoming_transactions(address, start_id)
|
|
16
|
+
if not transactions_json:
|
|
17
|
+
return
|
|
18
|
+
|
|
19
|
+
for transaction_json in transactions_json:
|
|
20
|
+
transaction_height = int(transaction_json['meta']['height'])
|
|
21
|
+
if start_height and transaction_height < start_height:
|
|
22
|
+
return
|
|
23
|
+
|
|
24
|
+
if end_height and transaction_height >= end_height:
|
|
25
|
+
continue
|
|
26
|
+
|
|
27
|
+
yield transaction_json
|
|
28
|
+
|
|
29
|
+
start_id = connector.extract_transaction_id(transactions_json[-1])
|
|
30
|
+
|
|
31
|
+
# endregion
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
# region filter_finalized_transactions
|
|
35
|
+
|
|
36
|
+
async def filter_finalized_transactions(connector, transaction_hashes):
|
|
37
|
+
"""Filters transaction hashes and returns only finalized ones with heights."""
|
|
38
|
+
|
|
39
|
+
finalized_chain_height = await connector.finalized_chain_height()
|
|
40
|
+
transaction_hash_height_pairs = await connector.filter_confirmed_transactions(transaction_hashes)
|
|
41
|
+
return list(filter(
|
|
42
|
+
lambda transaction_hash_height_pair: transaction_hash_height_pair[1] <= finalized_chain_height,
|
|
43
|
+
transaction_hash_height_pairs))
|
|
44
|
+
|
|
45
|
+
# endregion
|
|
46
|
+
|
|
47
|
+
|
|
48
|
+
# region query_block_timestamps
|
|
49
|
+
|
|
50
|
+
async def query_block_timestamps(connector, heights, async_limiter_arguments=DEFAULT_ASYNC_LIMITER_ARGUMENTS):
|
|
51
|
+
"""Finds the timestamps for all blocks with the specified heights."""
|
|
52
|
+
|
|
53
|
+
limiter = AsyncLimiter(*async_limiter_arguments)
|
|
54
|
+
|
|
55
|
+
async def get_block_height_timestamp_pair(height):
|
|
56
|
+
async with limiter:
|
|
57
|
+
block_json = await connector.block_headers(height)
|
|
58
|
+
timestamp = connector.extract_block_timestamp(block_json)
|
|
59
|
+
return (height, timestamp)
|
|
60
|
+
|
|
61
|
+
tasks = [get_block_height_timestamp_pair(height) for height in heights]
|
|
62
|
+
block_height_timestamp_pairs = await asyncio.gather(*tasks)
|
|
63
|
+
return block_height_timestamp_pairs
|
|
64
|
+
|
|
65
|
+
# endregion
|