safeheron-api-sdk-python 1.1.12__tar.gz → 1.1.14__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.
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/PKG-INFO +1 -1
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/transaction_api.py +6 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/cosigner/co_signer_converter.py +66 -11
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/tools.py +21 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python.egg-info/PKG-INFO +1 -1
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/setup.py +1 -1
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/LICENSE +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/README.rst +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/account_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/coin_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/mpc_sign_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/web3_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/webhook_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/api/whitelist_api.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/client.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python/webhook/webhook_converter.py +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python.egg-info/SOURCES.txt +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python.egg-info/dependency_links.txt +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python.egg-info/requires.txt +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/safeheron_api_sdk_python.egg-info/top_level.txt +0 -0
- {safeheron_api_sdk_python-1.1.12 → safeheron_api_sdk_python-1.1.14}/setup.cfg +0 -0
|
@@ -350,6 +350,12 @@ class TransactionApi:
|
|
|
350
350
|
request.asDict()
|
|
351
351
|
return self.api_client.send_request(request, '/v2/transactions/create')
|
|
352
352
|
|
|
353
|
+
# Create a new transaction.
|
|
354
|
+
|
|
355
|
+
def create_transactions_v3(self, request: CreateTransactionRequest):
|
|
356
|
+
request.asDict()
|
|
357
|
+
return self.api_client.send_request(request, '/v3/transactions/create')
|
|
358
|
+
|
|
353
359
|
# For UTXOs that natively support multiple OUTPUTs, this interface allows a single transaction to transfer funds to multiple destination addresses simultaneously.(To use the Co-Signer, please use version 1.5.9 or higher)
|
|
354
360
|
def create_transactions_UTXO_multiDest(self, request: CreateTransactionsUTXOMultiDestRequest):
|
|
355
361
|
request.asDict()
|
|
@@ -9,18 +9,33 @@ class CoSignerResponse:
|
|
|
9
9
|
self.txKey = None
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
class CoSignerResponseV3:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
# action
|
|
15
|
+
self.action = None
|
|
16
|
+
# approvalId
|
|
17
|
+
self.approvalId = None
|
|
18
|
+
|
|
19
|
+
|
|
12
20
|
class CoSignerConverter:
|
|
13
21
|
|
|
14
22
|
def __init__(self, config):
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
23
|
+
# Supports both coSignerPubKey and apiPublKey
|
|
24
|
+
self.co_signer_pub_key = config.get('coSignerPubKey') or config.get('apiPubKey')
|
|
25
|
+
|
|
26
|
+
# Supports both approvalCallbackServicePrivateKey and bizPrivKey
|
|
27
|
+
private_key = config.get('approvalCallbackServicePrivateKey') or config.get('bizPrivKey')
|
|
28
|
+
if private_key:
|
|
29
|
+
self.approval_callback_service_private_key = PEM_PRIVATE_HEAD + private_key + PEM_PRIVATE_END
|
|
30
|
+
|
|
31
|
+
# Supports both approvalCallbackServicePrivateKeyPemFile and bizPrivKeyPemFile
|
|
32
|
+
pem_file = config.get('approvalCallbackServicePrivateKeyPemFile') or config.get('bizPrivKeyPemFile')
|
|
33
|
+
if pem_file:
|
|
34
|
+
self.approval_callback_service_private_key = load_rsa_private_key(pem_file)
|
|
20
35
|
|
|
21
36
|
def request_convert(self, co_signer_call_back):
|
|
22
|
-
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.
|
|
23
|
-
api_user_rsa_sk = get_rsa_key(self.
|
|
37
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
|
|
38
|
+
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
|
|
24
39
|
required_keys = {
|
|
25
40
|
'key',
|
|
26
41
|
'sig',
|
|
@@ -65,10 +80,50 @@ class CoSignerConverter:
|
|
|
65
80
|
|
|
66
81
|
return json.loads(r.decode())
|
|
67
82
|
|
|
83
|
+
def request_v3_convert(self, co_signer_call_back):
|
|
84
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
|
|
85
|
+
required_keys = {
|
|
86
|
+
'version',
|
|
87
|
+
'sig',
|
|
88
|
+
'bizContent',
|
|
89
|
+
'timestamp',
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
missing_keys = required_keys.difference(co_signer_call_back.keys())
|
|
93
|
+
if missing_keys:
|
|
94
|
+
raise Exception(co_signer_call_back)
|
|
95
|
+
co_signer_call_back['version'] = 'v3'
|
|
96
|
+
sig = co_signer_call_back.pop('sig')
|
|
97
|
+
|
|
98
|
+
need_sign_message = sort_request(co_signer_call_back)
|
|
99
|
+
v = rsa_pass_verify(platform_rsa_pk, need_sign_message, sig)
|
|
100
|
+
if not v:
|
|
101
|
+
raise Exception("rsa verify: false")
|
|
102
|
+
return json.loads(b64decode(co_signer_call_back['bizContent']).decode())
|
|
103
|
+
|
|
104
|
+
def response_v3_converter(self, co_signer_response: CoSignerResponseV3):
|
|
105
|
+
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
|
|
106
|
+
ret = dict()
|
|
107
|
+
response_data = json.dumps(co_signer_response.__dict__).replace('\'', '\"').replace('\n', '').encode('utf-8')
|
|
108
|
+
|
|
109
|
+
if response_data is not None:
|
|
110
|
+
ret['bizContent'] = b64encode(response_data).decode()
|
|
111
|
+
|
|
112
|
+
ret['timestamp'] = str(int(time.time() * 1000))
|
|
113
|
+
ret['code'] = str('200')
|
|
114
|
+
ret['version'] = str('v3')
|
|
115
|
+
ret['message'] = str('SUCCESS')
|
|
116
|
+
|
|
117
|
+
# 4 sign request
|
|
118
|
+
need_sign_message = sort_request(ret)
|
|
119
|
+
ret['sig'] = rsa_pss_sign(api_user_rsa_sk, need_sign_message)
|
|
120
|
+
return ret
|
|
121
|
+
|
|
122
|
+
|
|
68
123
|
# It has been Deprecated,Please use convertCoSignerResponseWithNewCryptoType
|
|
69
124
|
def response_converter(self, co_signer_response: CoSignerResponse):
|
|
70
|
-
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.
|
|
71
|
-
api_user_rsa_sk = get_rsa_key(self.
|
|
125
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
|
|
126
|
+
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
|
|
72
127
|
|
|
73
128
|
ret = dict()
|
|
74
129
|
|
|
@@ -98,8 +153,8 @@ class CoSignerConverter:
|
|
|
98
153
|
return ret
|
|
99
154
|
|
|
100
155
|
def response_converter_with_new_crypto_type(self, co_signer_response: CoSignerResponse):
|
|
101
|
-
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.
|
|
102
|
-
api_user_rsa_sk = get_rsa_key(self.
|
|
156
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.co_signer_pub_key + PEM_PUBLIC_END)
|
|
157
|
+
api_user_rsa_sk = get_rsa_key(self.approval_callback_service_private_key)
|
|
103
158
|
|
|
104
159
|
ret = dict()
|
|
105
160
|
|
|
@@ -8,6 +8,7 @@ from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
|
|
|
8
8
|
from Cryptodome.Hash import SHA256, SHA1
|
|
9
9
|
from Cryptodome import Random
|
|
10
10
|
from Crypto.Cipher import PKCS1_OAEP
|
|
11
|
+
from Cryptodome.Signature import pss
|
|
11
12
|
import json
|
|
12
13
|
import time
|
|
13
14
|
import requests
|
|
@@ -147,6 +148,16 @@ def rsa_sign(private_key, message_hash: bytes):
|
|
|
147
148
|
except Exception as e:
|
|
148
149
|
raise Exception("rsa sign error: %s" % e)
|
|
149
150
|
|
|
151
|
+
def rsa_pss_sign(private_key, message_hash: bytes):
|
|
152
|
+
try:
|
|
153
|
+
signer = pss.new(private_key)
|
|
154
|
+
digest = SHA256.new()
|
|
155
|
+
digest.update(message_hash)
|
|
156
|
+
signed = signer.sign(digest)
|
|
157
|
+
return b64encode(signed).decode()
|
|
158
|
+
except Exception as e:
|
|
159
|
+
raise Exception("rsa sign error: %s" % e)
|
|
160
|
+
|
|
150
161
|
|
|
151
162
|
def rsa_verify(public_key, message_hash: bytes, signature):
|
|
152
163
|
try:
|
|
@@ -157,6 +168,16 @@ def rsa_verify(public_key, message_hash: bytes, signature):
|
|
|
157
168
|
except Exception as e:
|
|
158
169
|
raise Exception("rsa sign error: %s" % e)
|
|
159
170
|
|
|
171
|
+
def rsa_pass_verify(public_key, message_hash: bytes, signature):
|
|
172
|
+
try:
|
|
173
|
+
verifier = pss.new(public_key)
|
|
174
|
+
digest = SHA256.new()
|
|
175
|
+
digest.update(message_hash)
|
|
176
|
+
verifier.verify(digest, b64decode(signature))
|
|
177
|
+
return True
|
|
178
|
+
except Exception as e:
|
|
179
|
+
raise Exception("rsa sign error: %s" % e)
|
|
180
|
+
|
|
160
181
|
|
|
161
182
|
def sort_request(r: dict):
|
|
162
183
|
sortData = json.dumps(r, sort_keys=True).replace(' ', '')
|
|
@@ -3,7 +3,7 @@ from setuptools import find_packages
|
|
|
3
3
|
with open("README.rst", "r") as f:
|
|
4
4
|
long_description = f.read()
|
|
5
5
|
setup(name='safeheron_api_sdk_python',
|
|
6
|
-
version='1.1.
|
|
6
|
+
version='1.1.14',
|
|
7
7
|
description='Python for Safeheron API',
|
|
8
8
|
long_description=long_description,
|
|
9
9
|
author='safeheron',
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|