safeheron-api-sdk-python 1.1.18__py3-none-any.whl
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/api/account_api.py +272 -0
- safeheron_api_sdk_python/api/api_key_management_api.py +18 -0
- safeheron_api_sdk_python/api/coin_api.py +65 -0
- safeheron_api_sdk_python/api/gas_api.py +21 -0
- safeheron_api_sdk_python/api/mpc_sign_api.py +73 -0
- safeheron_api_sdk_python/api/tools_api.py +32 -0
- safeheron_api_sdk_python/api/transaction_api.py +399 -0
- safeheron_api_sdk_python/api/web3_api.py +279 -0
- safeheron_api_sdk_python/api/webhook_api.py +49 -0
- safeheron_api_sdk_python/api/whitelist_api.py +154 -0
- safeheron_api_sdk_python/client.py +28 -0
- safeheron_api_sdk_python/cosigner/co_signer_converter.py +185 -0
- safeheron_api_sdk_python/tools.py +335 -0
- safeheron_api_sdk_python/webhook/webhook_converter.py +58 -0
- safeheron_api_sdk_python-1.1.18.dist-info/METADATA +27 -0
- safeheron_api_sdk_python-1.1.18.dist-info/RECORD +19 -0
- safeheron_api_sdk_python-1.1.18.dist-info/WHEEL +5 -0
- safeheron_api_sdk_python-1.1.18.dist-info/licenses/LICENSE +21 -0
- safeheron_api_sdk_python-1.1.18.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,335 @@
|
|
|
1
|
+
from Cryptodome.Cipher import AES
|
|
2
|
+
from Cryptodome.Util.Padding import pad, unpad
|
|
3
|
+
from Cryptodome.PublicKey import RSA
|
|
4
|
+
from Cryptodome.Random import get_random_bytes
|
|
5
|
+
from base64 import b64encode, b64decode
|
|
6
|
+
from Cryptodome.Signature import PKCS1_v1_5 as Signature_pkcs1_v1_5
|
|
7
|
+
from Cryptodome.Cipher import PKCS1_v1_5 as Cipher_pkcs1_v1_5
|
|
8
|
+
from Cryptodome.Hash import SHA256, SHA1
|
|
9
|
+
from Cryptodome import Random
|
|
10
|
+
from Crypto.Cipher import PKCS1_OAEP
|
|
11
|
+
from Cryptodome.Signature import pss
|
|
12
|
+
import json
|
|
13
|
+
import time
|
|
14
|
+
import requests
|
|
15
|
+
from cryptography.hazmat.primitives import serialization
|
|
16
|
+
from cryptography.hazmat.backends import default_backend
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
PEM_PUBLIC_HEAD = "-----BEGIN PUBLIC KEY-----\n"
|
|
20
|
+
PEM_PUBLIC_END = "\n-----END PUBLIC KEY-----"
|
|
21
|
+
PEM_PRIVATE_HEAD = "-----BEGIN RSA PRIVATE KEY-----\n"
|
|
22
|
+
PEM_PRIVATE_END = "\n-----END RSA PRIVATE KEY-----"
|
|
23
|
+
|
|
24
|
+
|
|
25
|
+
GCM_TYPE = "GCM_NOPADDING"
|
|
26
|
+
ECB_OAEP_TYPE = "ECB_OAEP"
|
|
27
|
+
|
|
28
|
+
def load_rsa_private_key(file_path, password=None):
|
|
29
|
+
try:
|
|
30
|
+
with open(file_path, "rb") as key_file:
|
|
31
|
+
private_key = serialization.load_pem_private_key(
|
|
32
|
+
key_file.read(),
|
|
33
|
+
password=password,
|
|
34
|
+
backend=default_backend()
|
|
35
|
+
)
|
|
36
|
+
pem = private_key.private_bytes(
|
|
37
|
+
encoding=serialization.Encoding.PEM,
|
|
38
|
+
format=serialization.PrivateFormat.PKCS8,
|
|
39
|
+
encryption_algorithm=serialization.NoEncryption()
|
|
40
|
+
)
|
|
41
|
+
return pem.decode()
|
|
42
|
+
except Exception as e:
|
|
43
|
+
raise Exception("Failed to parse rsa pem file")
|
|
44
|
+
|
|
45
|
+
def check_key_and_iv(key: bytes, iv: bytes):
|
|
46
|
+
if len(key) != 32:
|
|
47
|
+
raise Exception("aes error: key must have 32 bytes")
|
|
48
|
+
if len(iv) != 16:
|
|
49
|
+
raise Exception("aes error: iv must have 16 bytes")
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def aes_encrypt(key: bytes, iv: bytes, message: bytes):
|
|
53
|
+
check_key_and_iv(key, iv)
|
|
54
|
+
message = pad(message, AES.block_size)
|
|
55
|
+
try:
|
|
56
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
57
|
+
encrypt_text = cipher.encrypt(message)
|
|
58
|
+
except Exception as e:
|
|
59
|
+
raise Exception("aes encrypt error: %s" % e)
|
|
60
|
+
return encrypt_text
|
|
61
|
+
|
|
62
|
+
|
|
63
|
+
def aes_gcm_encrypt(key: bytes, iv: bytes, message: bytes):
|
|
64
|
+
check_key_and_iv(key, iv)
|
|
65
|
+
try:
|
|
66
|
+
cipher = AES.new(key, AES.MODE_GCM, iv)
|
|
67
|
+
cipher_text, tag = cipher.encrypt_and_digest(message)
|
|
68
|
+
except Exception as e:
|
|
69
|
+
raise Exception("aes encrypt error: %s" % e)
|
|
70
|
+
return cipher_text + tag
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
def aes_decrypt(key: bytes, iv: bytes, encrypt_text: bytes):
|
|
74
|
+
check_key_and_iv(key, iv)
|
|
75
|
+
try:
|
|
76
|
+
cipher = AES.new(key, AES.MODE_CBC, iv)
|
|
77
|
+
pad_text = cipher.decrypt(encrypt_text)
|
|
78
|
+
except Exception as e:
|
|
79
|
+
raise Exception("aes decrypt error: %s" % e)
|
|
80
|
+
return unpad(pad_text, AES.block_size)
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
def aes_gcm_decrypt(key: bytes, iv: bytes, encrypt_text: bytes):
|
|
84
|
+
check_key_and_iv(key, iv)
|
|
85
|
+
try:
|
|
86
|
+
cipher = AES.new(key, AES.MODE_GCM, iv)
|
|
87
|
+
pad_text = cipher.decrypt(encrypt_text)
|
|
88
|
+
except Exception as e:
|
|
89
|
+
raise Exception("aes decrypt error: %s" % e)
|
|
90
|
+
return pad_text[0:len(pad_text)-len(iv)]
|
|
91
|
+
|
|
92
|
+
|
|
93
|
+
def get_rsa_key(key_pem, passphrase=None):
|
|
94
|
+
if key_pem == '':
|
|
95
|
+
raise Exception("rsa encrypt error: pubkey can't be none")
|
|
96
|
+
if passphrase is None:
|
|
97
|
+
return RSA.import_key(key_pem)
|
|
98
|
+
else:
|
|
99
|
+
return RSA.import_key(key_pem, passphrase=passphrase)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def rsa_encrypt(public_key, message: bytes):
|
|
103
|
+
try:
|
|
104
|
+
cipher_rsa = Cipher_pkcs1_v1_5.new(public_key)
|
|
105
|
+
encrypt_text = cipher_rsa.encrypt(message)
|
|
106
|
+
except Exception as e:
|
|
107
|
+
raise Exception("rsa encrypt error: %s" % e)
|
|
108
|
+
encrypt_text_base64 = b64encode(encrypt_text)
|
|
109
|
+
return encrypt_text_base64.decode('utf-8')
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def rsa_oaep_encrypt(public_key, message: bytes):
|
|
113
|
+
try:
|
|
114
|
+
cipher = PKCS1_OAEP.new(public_key, hashAlgo=SHA256)
|
|
115
|
+
encrypt_text = cipher.encrypt(message)
|
|
116
|
+
except Exception as e:
|
|
117
|
+
raise Exception("rsa encrypt error: %s" % e)
|
|
118
|
+
encrypt_text_base64 = b64encode(encrypt_text)
|
|
119
|
+
return encrypt_text_base64.decode('utf-8')
|
|
120
|
+
|
|
121
|
+
|
|
122
|
+
def rsa_decrypt(private_key, message: str):
|
|
123
|
+
encrypt_text = b64decode(message)
|
|
124
|
+
try:
|
|
125
|
+
cipher_rsa = Cipher_pkcs1_v1_5.new(private_key)
|
|
126
|
+
sentinel = Random.new().read(SHA1.digest_size)
|
|
127
|
+
return cipher_rsa.decrypt(encrypt_text, sentinel)
|
|
128
|
+
except Exception as e:
|
|
129
|
+
raise Exception("rsa decrypt error: %s" % e)
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
def rsa_oaep_decrypt(private_key, message: str):
|
|
133
|
+
encrypt_text = b64decode(message)
|
|
134
|
+
try:
|
|
135
|
+
cipher_rsa = PKCS1_OAEP.new(private_key, hashAlgo=SHA256)
|
|
136
|
+
return cipher_rsa.decrypt(encrypt_text)
|
|
137
|
+
except Exception as e:
|
|
138
|
+
raise Exception("rsa decrypt error: %s" % e)
|
|
139
|
+
|
|
140
|
+
|
|
141
|
+
def rsa_sign(private_key, message_hash: bytes):
|
|
142
|
+
try:
|
|
143
|
+
signer = Signature_pkcs1_v1_5.new(private_key)
|
|
144
|
+
digest = SHA256.new()
|
|
145
|
+
digest.update(message_hash)
|
|
146
|
+
signed = signer.sign(digest)
|
|
147
|
+
return b64encode(signed).decode()
|
|
148
|
+
except Exception as e:
|
|
149
|
+
raise Exception("rsa sign error: %s" % e)
|
|
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
|
+
|
|
161
|
+
|
|
162
|
+
def rsa_verify(public_key, message_hash: bytes, signature):
|
|
163
|
+
try:
|
|
164
|
+
signer = Signature_pkcs1_v1_5.new(public_key)
|
|
165
|
+
digest = SHA256.new()
|
|
166
|
+
digest.update(message_hash)
|
|
167
|
+
return signer.verify(digest, b64decode(signature))
|
|
168
|
+
except Exception as e:
|
|
169
|
+
raise Exception("rsa sign error: %s" % e)
|
|
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
|
+
|
|
181
|
+
|
|
182
|
+
def sort_request(r: dict):
|
|
183
|
+
sortData = json.dumps(r, sort_keys=True).replace(' ', '')
|
|
184
|
+
strArr = []
|
|
185
|
+
data1 = json.loads(sortData)
|
|
186
|
+
for key, value in data1.items():
|
|
187
|
+
# print(value, type(value))
|
|
188
|
+
if isinstance(value, dict):
|
|
189
|
+
val = json.dumps(value).replace(' ', '')
|
|
190
|
+
else:
|
|
191
|
+
val = value
|
|
192
|
+
strArr.append(key + '=' + str(val))
|
|
193
|
+
return "&".join(strArr).encode('utf-8')
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
def encrypt_request(api_key, request_dict, platform_rsa_pk, api_user_rsa_sk):
|
|
197
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + platform_rsa_pk + PEM_PUBLIC_END)
|
|
198
|
+
api_user_rsa_sk = get_rsa_key(api_user_rsa_sk)
|
|
199
|
+
|
|
200
|
+
ret = dict()
|
|
201
|
+
|
|
202
|
+
ret['apiKey'] = api_key
|
|
203
|
+
|
|
204
|
+
# prepare aes key and iv
|
|
205
|
+
aes_key = get_random_bytes(32)
|
|
206
|
+
aes_iv = get_random_bytes(16)
|
|
207
|
+
|
|
208
|
+
|
|
209
|
+
# 1 rsa encrypt aes key + iv
|
|
210
|
+
aes_data = aes_key + aes_iv
|
|
211
|
+
ret['key'] = rsa_oaep_encrypt(platform_rsa_pk, aes_data)
|
|
212
|
+
|
|
213
|
+
# 2 aes encrypt request data
|
|
214
|
+
if request_dict is not None:
|
|
215
|
+
request_data = json.dumps(request_dict.__dict__).replace('\'', '\"').replace('\n', '').encode('utf-8')
|
|
216
|
+
aes_encrypted_bytes = aes_gcm_encrypt(aes_key, aes_iv, request_data)
|
|
217
|
+
ret['bizContent'] = b64encode(aes_encrypted_bytes).decode()
|
|
218
|
+
|
|
219
|
+
# 3 set timestamp
|
|
220
|
+
ret['timestamp'] = str(int(time.time() * 1000))
|
|
221
|
+
|
|
222
|
+
# 4 sign request
|
|
223
|
+
need_sign_message = sort_request(ret)
|
|
224
|
+
ret['sig'] = rsa_sign(api_user_rsa_sk, need_sign_message)
|
|
225
|
+
ret['rsaType'] = ECB_OAEP_TYPE
|
|
226
|
+
ret['aesType'] = GCM_TYPE
|
|
227
|
+
return ret
|
|
228
|
+
|
|
229
|
+
|
|
230
|
+
def decrypt_response(response_dict, platform_rsa_pk, api_user_rsa_sk):
|
|
231
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + platform_rsa_pk + PEM_PUBLIC_END)
|
|
232
|
+
api_user_rsa_sk = get_rsa_key(api_user_rsa_sk)
|
|
233
|
+
required_keys = {
|
|
234
|
+
'key',
|
|
235
|
+
'sig',
|
|
236
|
+
'bizContent',
|
|
237
|
+
'timestamp',
|
|
238
|
+
'code',
|
|
239
|
+
'message'
|
|
240
|
+
}
|
|
241
|
+
missing_keys = required_keys.difference(response_dict.keys())
|
|
242
|
+
if missing_keys:
|
|
243
|
+
raise Exception(response_dict)
|
|
244
|
+
|
|
245
|
+
# 1 rsa verify
|
|
246
|
+
rsaType = ''
|
|
247
|
+
if "rsaType" in response_dict:
|
|
248
|
+
rsaType = response_dict.pop('rsaType')
|
|
249
|
+
|
|
250
|
+
aesType = ''
|
|
251
|
+
if "aesType" in response_dict:
|
|
252
|
+
aesType = response_dict.pop('aesType')
|
|
253
|
+
|
|
254
|
+
sig = response_dict.pop('sig')
|
|
255
|
+
need_sign_message = sort_request(response_dict)
|
|
256
|
+
v = rsa_verify(platform_rsa_pk, need_sign_message, sig)
|
|
257
|
+
if not v:
|
|
258
|
+
raise Exception("rsa verify: false")
|
|
259
|
+
|
|
260
|
+
# 2 get aes key and iv
|
|
261
|
+
key = response_dict.pop('key')
|
|
262
|
+
if ECB_OAEP_TYPE == rsaType:
|
|
263
|
+
aes_data = rsa_oaep_decrypt(api_user_rsa_sk, key)
|
|
264
|
+
else:
|
|
265
|
+
aes_data = rsa_decrypt(api_user_rsa_sk, key)
|
|
266
|
+
aes_key = aes_data[0:32]
|
|
267
|
+
aes_iv = aes_data[32:48]
|
|
268
|
+
|
|
269
|
+
# 3 aes decrypt data, get response data
|
|
270
|
+
if GCM_TYPE == aesType:
|
|
271
|
+
r = aes_gcm_decrypt(aes_key, aes_iv, b64decode(response_dict['bizContent']))
|
|
272
|
+
else:
|
|
273
|
+
r = aes_decrypt(aes_key, aes_iv, b64decode(response_dict['bizContent']))
|
|
274
|
+
#response_dict['bizContent'] = json.loads(r.decode())
|
|
275
|
+
|
|
276
|
+
return json.loads(r.decode())
|
|
277
|
+
|
|
278
|
+
#Used for webhook decryption callback request data
|
|
279
|
+
def decrypt_request(response_dict, verify_rsa_pk, decrypt_rsa_sk):
|
|
280
|
+
verify_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + verify_rsa_pk + PEM_PUBLIC_END)
|
|
281
|
+
decrypt_rsa_sk = get_rsa_key(decrypt_rsa_sk)
|
|
282
|
+
# 1 rsa verify
|
|
283
|
+
sig = response_dict.pop('sig')
|
|
284
|
+
need_sign_message = sort_request(response_dict)
|
|
285
|
+
v = rsa_verify(verify_rsa_pk, need_sign_message, sig)
|
|
286
|
+
if not v:
|
|
287
|
+
raise Exception("rsa verify: false")
|
|
288
|
+
|
|
289
|
+
# 2 get aes key and iv
|
|
290
|
+
aes_data = rsa_decrypt(decrypt_rsa_sk, response_dict['key'])
|
|
291
|
+
aes_key = aes_data[0:32]
|
|
292
|
+
aes_iv = aes_data[32:48]
|
|
293
|
+
|
|
294
|
+
# 3 aes decrypt data, get response data
|
|
295
|
+
r = aes_decrypt(aes_key, aes_iv, b64decode(response_dict['bizContent']))
|
|
296
|
+
|
|
297
|
+
return json.loads(r.decode())
|
|
298
|
+
|
|
299
|
+
#For webhook to send encrypted response content
|
|
300
|
+
def encrypt_response(raw_data,encrpyt_rsa_pk, sign_rsa_sk):
|
|
301
|
+
encrpyt_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + encrpyt_rsa_pk + PEM_PUBLIC_END)
|
|
302
|
+
sign_rsa_sk = get_rsa_key(sign_rsa_sk)
|
|
303
|
+
ret = dict()
|
|
304
|
+
# prepare aes key and iv
|
|
305
|
+
aes_key = get_random_bytes(32)
|
|
306
|
+
aes_iv = get_random_bytes(16)
|
|
307
|
+
res_data = json.dumps(raw_data).replace('\n', '').encode('utf-8')
|
|
308
|
+
|
|
309
|
+
# 1 rsa encrypt aes key + iv
|
|
310
|
+
aes_data = aes_key + aes_iv
|
|
311
|
+
ret['key'] = rsa_encrypt(encrpyt_rsa_pk, aes_data)
|
|
312
|
+
|
|
313
|
+
# 2 aes encrypt request data
|
|
314
|
+
aes_encrypted_bytes = aes_encrypt(aes_key, aes_iv, res_data)
|
|
315
|
+
ret['bizContent'] = b64encode(aes_encrypted_bytes).decode()
|
|
316
|
+
|
|
317
|
+
# 3 set timestamp , no need to add
|
|
318
|
+
ret['timestamp'] = str(int(time.time() * 1000))
|
|
319
|
+
|
|
320
|
+
# 4 code
|
|
321
|
+
ret['code'] = "200"
|
|
322
|
+
|
|
323
|
+
# 5 message
|
|
324
|
+
ret['message'] = "callback_ok"
|
|
325
|
+
|
|
326
|
+
# 6 sign request
|
|
327
|
+
need_sign_message = sort_request(ret)
|
|
328
|
+
ret['sig'] = rsa_sign(sign_rsa_sk, need_sign_message)
|
|
329
|
+
return ret
|
|
330
|
+
|
|
331
|
+
def rsa_gen_key():
|
|
332
|
+
rsa_key = RSA.generate(4096)
|
|
333
|
+
sk = rsa_key.export_key()
|
|
334
|
+
pk = rsa_key.publickey().export_key()
|
|
335
|
+
return sk, pk
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
from safeheron_api_sdk_python.tools import *
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class WebhookConverter:
|
|
5
|
+
|
|
6
|
+
def __init__(self, config):
|
|
7
|
+
self.safeheron_webHook_rsa_public_key = config['safeheronWebHookRsaPublicKey']
|
|
8
|
+
if config.get('webHookRsaPrivateKey'):
|
|
9
|
+
self.web_hook_rsa_private_key = PEM_PRIVATE_HEAD + config['webHookRsaPrivateKey'] + PEM_PRIVATE_END
|
|
10
|
+
if config.get('webHookRsaPrivateKeyPemFile'):
|
|
11
|
+
self.web_hook_rsa_private_key = load_rsa_private_key(config['webHookRsaPrivateKeyPemFile'])
|
|
12
|
+
|
|
13
|
+
def converter(self, webhook):
|
|
14
|
+
platform_rsa_pk = get_rsa_key(PEM_PUBLIC_HEAD + self.safeheron_webHook_rsa_public_key + PEM_PUBLIC_END)
|
|
15
|
+
api_user_rsa_sk = get_rsa_key(self.web_hook_rsa_private_key)
|
|
16
|
+
required_keys = {
|
|
17
|
+
'key',
|
|
18
|
+
'sig',
|
|
19
|
+
'bizContent',
|
|
20
|
+
'timestamp',
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
missing_keys = required_keys.difference(webhook.keys())
|
|
24
|
+
if missing_keys:
|
|
25
|
+
raise Exception(webhook)
|
|
26
|
+
|
|
27
|
+
# 1 rsa verify
|
|
28
|
+
rsaType = ''
|
|
29
|
+
if "rsaType" in webhook:
|
|
30
|
+
rsaType = webhook.pop('rsaType')
|
|
31
|
+
|
|
32
|
+
aesType = ''
|
|
33
|
+
if "aesType" in webhook:
|
|
34
|
+
aesType = webhook.pop('aesType')
|
|
35
|
+
|
|
36
|
+
sig = webhook.pop('sig')
|
|
37
|
+
need_sign_message = sort_request(webhook)
|
|
38
|
+
v = rsa_verify(platform_rsa_pk, need_sign_message, sig)
|
|
39
|
+
if not v:
|
|
40
|
+
raise Exception("rsa verify: false")
|
|
41
|
+
|
|
42
|
+
# 2 get aes key and iv
|
|
43
|
+
key = webhook.pop('key')
|
|
44
|
+
if ECB_OAEP_TYPE == rsaType:
|
|
45
|
+
aes_data = rsa_oaep_decrypt(api_user_rsa_sk, key)
|
|
46
|
+
else:
|
|
47
|
+
aes_data = rsa_decrypt(api_user_rsa_sk, key)
|
|
48
|
+
aes_key = aes_data[0:32]
|
|
49
|
+
aes_iv = aes_data[32:48]
|
|
50
|
+
|
|
51
|
+
# 3 aes decrypt data, get response data
|
|
52
|
+
if GCM_TYPE == aesType:
|
|
53
|
+
r = aes_gcm_decrypt(aes_key, aes_iv, b64decode(webhook['bizContent']))
|
|
54
|
+
else:
|
|
55
|
+
r = aes_decrypt(aes_key, aes_iv, b64decode(webhook['bizContent']))
|
|
56
|
+
# response_dict['bizContent'] = json.loads(r.decode())
|
|
57
|
+
|
|
58
|
+
return json.loads(r.decode())
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: safeheron_api_sdk_python
|
|
3
|
+
Version: 1.1.18
|
|
4
|
+
Summary: Python for Safeheron API
|
|
5
|
+
Home-page: https://github.com/Safeheron/safeheron-api-sdk-python
|
|
6
|
+
Author: safeheron
|
|
7
|
+
Author-email: support@safeheron.com
|
|
8
|
+
License: MIT License
|
|
9
|
+
Platform: all
|
|
10
|
+
Classifier: Operating System :: OS Independent
|
|
11
|
+
Classifier: Programming Language :: Python :: 3
|
|
12
|
+
License-File: LICENSE
|
|
13
|
+
Requires-Dist: pycryptodomex
|
|
14
|
+
Requires-Dist: requests
|
|
15
|
+
Requires-Dist: cryptography
|
|
16
|
+
Dynamic: author
|
|
17
|
+
Dynamic: author-email
|
|
18
|
+
Dynamic: classifier
|
|
19
|
+
Dynamic: description
|
|
20
|
+
Dynamic: home-page
|
|
21
|
+
Dynamic: license
|
|
22
|
+
Dynamic: license-file
|
|
23
|
+
Dynamic: platform
|
|
24
|
+
Dynamic: requires-dist
|
|
25
|
+
Dynamic: summary
|
|
26
|
+
|
|
27
|
+
# Python SDK for Safeheron API
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
safeheron_api_sdk_python/client.py,sha256=kIRknW1YAhgKAl9hxQ7VQuMfwdeUh_VJrUnuxOX1cxs,1192
|
|
2
|
+
safeheron_api_sdk_python/tools.py,sha256=5a5IJXE4U9AcMEju6uLXAgW-7dpBE6qOLLZdVe_9WNg,10930
|
|
3
|
+
safeheron_api_sdk_python/api/account_api.py,sha256=p-6dNcxETdxcwuZlYBkzfMc8hc8cz8DmaXV2tXPme5A,12250
|
|
4
|
+
safeheron_api_sdk_python/api/api_key_management_api.py,sha256=X1_-bskqZN8LyIAe4HoEFw6tVZc9m-P0jZv00tLX2Po,1270
|
|
5
|
+
safeheron_api_sdk_python/api/coin_api.py,sha256=2emU9ZdGJeQwLsM9r9niaT3f_2vT1i_cykqzZgNyyp4,2648
|
|
6
|
+
safeheron_api_sdk_python/api/gas_api.py,sha256=TX_kinHrZt1Y8VTIe5RdbmBrV2Ht4LW6cQz4n2HlMu4,1152
|
|
7
|
+
safeheron_api_sdk_python/api/mpc_sign_api.py,sha256=sxFJPVV4azF4raWxtt4oUC5bEu3cp_ZBMMbjnlOJ5CM,3456
|
|
8
|
+
safeheron_api_sdk_python/api/tools_api.py,sha256=yqLfxmVjq24cp-pkj-iSIWK_ZHCv6Zkwf6EymzLuV7A,972
|
|
9
|
+
safeheron_api_sdk_python/api/transaction_api.py,sha256=4B7Skq2tEoMfMHeyLj9NhqoB2x6OABtRPZf9Ox05VY0,19762
|
|
10
|
+
safeheron_api_sdk_python/api/web3_api.py,sha256=glMr7e_Gzz8zXv5GH9v1ASGylALxHK3wh9vADv7zvDg,12565
|
|
11
|
+
safeheron_api_sdk_python/api/webhook_api.py,sha256=HQi1Y4MHYzjPZEF_CfLp-3kG_trn8Of7ojKpxxFTPmo,3529
|
|
12
|
+
safeheron_api_sdk_python/api/whitelist_api.py,sha256=xmsKjkANqE-Np3VRQjftXqFvYiPP4SOnuXU2Z-m02Zg,9555
|
|
13
|
+
safeheron_api_sdk_python/cosigner/co_signer_converter.py,sha256=rQ5NK2fns0oZXi_gmFNAIJAaJOgMO87we_8sTK3XbPg,6928
|
|
14
|
+
safeheron_api_sdk_python/webhook/webhook_converter.py,sha256=_TJH9B1nsusysDOa7iAPTccKJ0v1eQOYA5vAq0Qk-bg,2074
|
|
15
|
+
safeheron_api_sdk_python-1.1.18.dist-info/licenses/LICENSE,sha256=jmur70PCz0N4z2UiEwoFuZbCfilZhc-2H5KfuEYKqO0,1071
|
|
16
|
+
safeheron_api_sdk_python-1.1.18.dist-info/METADATA,sha256=La6X9BswB2VjPRUEbxF2yXGSOiwLYK7pxTJpV8Op4Gg,682
|
|
17
|
+
safeheron_api_sdk_python-1.1.18.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
safeheron_api_sdk_python-1.1.18.dist-info/top_level.txt,sha256=P7fhd_ESNNrP0csqebAfcWq3hfRJrBuDIlVD1KXHTeY,25
|
|
19
|
+
safeheron_api_sdk_python-1.1.18.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2022 Safeheron Inc.
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
safeheron_api_sdk_python
|