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,49 @@
|
|
|
1
|
+
from safeheron_api_sdk_python.client import *
|
|
2
|
+
|
|
3
|
+
class ResendWebhookRequest:
|
|
4
|
+
def __init__(self):
|
|
5
|
+
# Supported events:
|
|
6
|
+
# TRANSACTION
|
|
7
|
+
# MPC_SIGN
|
|
8
|
+
# WEB3_SIGN
|
|
9
|
+
self.category = None
|
|
10
|
+
# Transaction key
|
|
11
|
+
self.txKey = None
|
|
12
|
+
|
|
13
|
+
class ResendFailedRequest:
|
|
14
|
+
def __init__(self):
|
|
15
|
+
# Start time in UNIX timestamp (ms). The time interval [startTime, endTime] is up to 1 hour
|
|
16
|
+
self.startTime = None
|
|
17
|
+
# End time in UNIX timestamp (ms). The time interval [startTime, endTime] is up to 1 hour
|
|
18
|
+
self.endTime = None
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
class WebhookApi:
|
|
22
|
+
|
|
23
|
+
def __init__(self, config):
|
|
24
|
+
self.api_client = Client(config)
|
|
25
|
+
# Re-push Transaction Webhook Events
|
|
26
|
+
# Re-push the transaction webhook events generated in the last month. In certain situations, such as network jitter or your system being unavailable to receive webhook events, you may miss receiving notifications. You can use this interface to notify Safeheron to re-push the webhook events. It is important to note that for a single transaction, only the last webhook event will be re-pushed. For example, during the lifecycle of a transaction, multiple TRANSACTION_STATUS_CHANGED webhook events such as BROADCASTING, CONFIRMING, COMPLETED, etc., may be generated. The re-push will only send the last webhook event recorded by the current system. Re-pushing is supported for the following types of webhook events:
|
|
27
|
+
# Events related to asset transactions, including TRANSACTION_CREATED and TRANSACTION_STATUS_CHANGED.
|
|
28
|
+
# Events related to MPC signing, including MPC_SIGN_CREATED and MPC_SIGN_STATUS_CHANGED.
|
|
29
|
+
# Events related to Web3, including WEB3_SIGN_CREATED and WEB3_SIGN_STATUS_CHANGED.
|
|
30
|
+
# More types of webhook events will be supported in the future.
|
|
31
|
+
def resend_webhook(self, request: ResendWebhookRequest):
|
|
32
|
+
return self.api_client.send_request(request, '/v1/webhook/resend')
|
|
33
|
+
|
|
34
|
+
# Push All Failed Webhook Events
|
|
35
|
+
# Resend all webhook events that failed to push within any duration not exceeding 1 hour in the past 7 days (limited to 1 call every 10 minutes). In certain situations, such as network failures or your system being unavailable to receive webhook events, you may miss receiving notifications. Once the issue is resolved, you can use this interface to notify Safeheron to resend all webhook events that failed to push within a certain period. Support re-pushing the following types of webhook events:
|
|
36
|
+
# TRANSACTION_CREATED
|
|
37
|
+
# TRANSACTION_STATUS_CHANGED
|
|
38
|
+
# MPC_SIGN_CREATED
|
|
39
|
+
# MPC_SIGN_STATUS_CHANGED
|
|
40
|
+
# WEB3_SIGN_CREATED
|
|
41
|
+
# WEB3_SIGN_STATUS_CHANGED
|
|
42
|
+
# ILLEGAL_IP_REQUEST
|
|
43
|
+
# NO_MATCHING_TRANSACTION_POLICY
|
|
44
|
+
# More types of webhook events will be supported in the future.
|
|
45
|
+
# Please note that when re-pushing all failed webhook events, your system needs to avoid rollback issues. For example, during the lifecycle of a transaction, multiple TRANSACTION_STATUS_CHANGED webhook events may be generated, such as BROADCASTING, CONFIRMING, and COMPLETED. If your system did not receive the CONFIRMING event due to network issues but did receive the COMPLETED event, using this interface would cause Safeheron to attempt resending the CONFIRMING event to your system. Your system needs to ensure that the transaction does not incorrectly revert from the COMPLETED status back to the CONFIRMING status.
|
|
46
|
+
def resend_failed(self, request: ResendFailedRequest):
|
|
47
|
+
return self.api_client.send_request(request, '/v1/webhook/resend/failed')
|
|
48
|
+
|
|
49
|
+
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
from safeheron_api_sdk_python.client import *
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class ListWhitelistRequest:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
# Query page direction, NEXT by default
|
|
7
|
+
self.direct = None
|
|
8
|
+
# The number of items to retrieve at a time, default max value is 500
|
|
9
|
+
self.limit = None
|
|
10
|
+
# Txkey of the first transaction record. If the first page has no value, provide the txKey of the last transaction record from the previous result
|
|
11
|
+
self.fromId = None
|
|
12
|
+
# The supported public blockchains for whitelist addresses are:
|
|
13
|
+
# EVM: Ethereum-compatible public chain networks or Layer 2 addresses that can receive its native token and other tokens
|
|
14
|
+
# Bitcoin: Bitcoin mainnet addresses that can receive Bitcoin
|
|
15
|
+
# Bitcoin Cash: Bitcoin Cash network, which can receive BCH
|
|
16
|
+
# Dash: anonymous Dash network, which can receive DASH
|
|
17
|
+
# TRON: Tron mainnet addresses, which can receive TRX and TRC20 tokens, such as USDT and USDC
|
|
18
|
+
# NEAR: NEAR mainnet, which can receive native token NEAR
|
|
19
|
+
# Filecoin: Receive Filecoin native token FIL, but does not support receiving FIL or tokens from the FVM network
|
|
20
|
+
# Sui: Sui mainnet, which can receive native token Sui and other tokens
|
|
21
|
+
# Aptos: Aptos mainnet, which only supports receiving native token Aptos and does not support other tokens yet
|
|
22
|
+
# Solana: Solana mainnet, which can receive native token SOL and other tokens
|
|
23
|
+
# Bitcoin Testnet: Bitcoin testnet, which can receive Bitcoin testnet ass
|
|
24
|
+
self.chainType = None
|
|
25
|
+
# Whitelist status
|
|
26
|
+
# AUDIT: pending approval
|
|
27
|
+
# APPROVED: active
|
|
28
|
+
# REJECTED: rejected
|
|
29
|
+
self.whitelistStatus = None
|
|
30
|
+
# Start time for creating a whitelist in UNIX timestamp (ms) (If no value is provided, the default value is createTimeMax minus 24 hours)
|
|
31
|
+
self.createTimeMin = None
|
|
32
|
+
# End time for creating a whitelist in UNIX timestamp (ms) (If no value is provided, the default value is the current UTC time)
|
|
33
|
+
self.createTimeMax = None
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OneWhitelistRequest:
|
|
37
|
+
def __init__(self):
|
|
38
|
+
# Whitelist unique identifier. It is required if address is not provided. If both are provided, the whitelistKey takes precedence
|
|
39
|
+
self.whitelistKey = None
|
|
40
|
+
# Whitelist address. It is required if whitelistKey is not provided and please make sure the provided address is correct
|
|
41
|
+
self.address = None
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
class CreateWhitelistRequest:
|
|
45
|
+
def __init__(self):
|
|
46
|
+
# Whitelist unique name, 20 characters max
|
|
47
|
+
self.whitelistName = None
|
|
48
|
+
# The supported public blockchains for whitelist addresses are:
|
|
49
|
+
# EVM: Ethereum-compatible public chain networks or Layer 2 addresses that can receive its native token and other tokens
|
|
50
|
+
# Bitcoin: Bitcoin mainnet addresses that can receive Bitcoin
|
|
51
|
+
# Bitcoin Cash: Bitcoin Cash network, which can receive BCH
|
|
52
|
+
# Dash: anonymous Dash network, which can receive DASH
|
|
53
|
+
# TRON: Tron mainnet addresses, which can receive TRX and TRC20 tokens, such as USDT and USDC
|
|
54
|
+
# NEAR: NEAR mainnet, which can receive native token NEAR
|
|
55
|
+
# Filecoin: Receive Filecoin native token FIL, but does not support receiving FIL or tokens from the FVM network
|
|
56
|
+
# Sui: Sui mainnet, which can receive native token Sui and other tokens
|
|
57
|
+
# Aptos: Aptos mainnet, which only supports receiving native token Aptos and does not support other tokens yet
|
|
58
|
+
# Solana: Solana mainnet, which can receive native token SOL and other tokens
|
|
59
|
+
# Bitcoin Testnet: Bitcoin testnet, which can receive Bitcoin testnet assets
|
|
60
|
+
self.chainType = None
|
|
61
|
+
# Public blockchain address and the address format needs to meet the requirements of the chain
|
|
62
|
+
self.address = None
|
|
63
|
+
# The memo (up to 20 characters) for the destination address, also known as a comment or tag. For the following networks, if a destination address memo was set initially, a memo matching the one in the transaction record must be provided
|
|
64
|
+
# TON: TON mainnet
|
|
65
|
+
# TON_TESTNET: TON testnet
|
|
66
|
+
self.memo = None
|
|
67
|
+
# Visibility status in Safeheron App and Web Console
|
|
68
|
+
# False: Visible by default
|
|
69
|
+
# True: Invisible; the invisible whitelist can only be managed and used through the API, such as querying, modifying, and using the whitelist as the destination address when initiating transactions
|
|
70
|
+
self.hiddenOnUI = None
|
|
71
|
+
|
|
72
|
+
|
|
73
|
+
class CreateFromTransactionWhitelistRequest:
|
|
74
|
+
def __init__(self):
|
|
75
|
+
# Whitelist unique name, 20 characters max
|
|
76
|
+
self.whitelistName = None
|
|
77
|
+
# Transaction key
|
|
78
|
+
self.txKey = None
|
|
79
|
+
# The destination address in the transaction record; case-sensitive
|
|
80
|
+
self.destinationAddress = None
|
|
81
|
+
# The memo (up to 20 characters) for the destination address, also known as a comment or tag. For the following networks, if a destination address memo was set initially, a memo matching the one in the transaction record must be provided
|
|
82
|
+
# TON: TON mainnet
|
|
83
|
+
# TON_TESTNET: TON testnet
|
|
84
|
+
self.memo = None
|
|
85
|
+
# Visibility status in Safeheron App and Web Console
|
|
86
|
+
# False: Visible by default
|
|
87
|
+
# True: Invisible; the invisible whitelist can only be managed and used through the API, such as querying, modifying, and using the whitelist as the destination address when initiating transactions
|
|
88
|
+
self.hiddenOnUI = None
|
|
89
|
+
|
|
90
|
+
|
|
91
|
+
class EditWhitelistRequest:
|
|
92
|
+
def __init__(self):
|
|
93
|
+
# Whitelist unique identifier
|
|
94
|
+
self.whitelistKey = None
|
|
95
|
+
# Whitelist unique name, 20 characters max
|
|
96
|
+
self.whitelistName = None
|
|
97
|
+
# Public blockchain address and the address format needs to meet the requirements of the chain
|
|
98
|
+
self.address = None
|
|
99
|
+
# The memo (up to 20 characters) for the destination address, also known as a comment or tag. For the following networks, if a destination address memo was set initially, a memo matching the one in the transaction record must be provided
|
|
100
|
+
# TON: TON mainnet
|
|
101
|
+
# TON_TESTNET: TON testnet
|
|
102
|
+
self.memo = None
|
|
103
|
+
# When the whitelist is involved in a transaction approval policy, modifications will result in the new whitelist being directly applied to the approval policy. False by default, meaning that when involved in a transaction approval policy, it will not be modified.
|
|
104
|
+
self.force = None
|
|
105
|
+
|
|
106
|
+
|
|
107
|
+
class DeleteWhitelistRequest:
|
|
108
|
+
def __init__(self):
|
|
109
|
+
# Whitelist unique identifier
|
|
110
|
+
self.whitelistKey = None
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
class WhitelistApi:
|
|
114
|
+
|
|
115
|
+
def __init__(self, config):
|
|
116
|
+
self.api_client = Client(config)
|
|
117
|
+
|
|
118
|
+
# List Whitelist Data
|
|
119
|
+
# Paginate the whitelist data based on the query criteria.
|
|
120
|
+
def list_whitelist(self, request: ListWhitelistRequest):
|
|
121
|
+
return self.api_client.send_request(request, '/v1/whitelist/list')
|
|
122
|
+
|
|
123
|
+
# Retrieve a Single Whitelist
|
|
124
|
+
# * Retrieve the data of a whitelist.
|
|
125
|
+
def one_whitelist(self, request: OneWhitelistRequest):
|
|
126
|
+
return self.api_client.send_request(request, '/v1/whitelist/one')
|
|
127
|
+
|
|
128
|
+
# Create a Whitelist
|
|
129
|
+
# Add a new whitelisted address. The newly added address needs to be approved in the Safeheron App before it becomes effective. The approval details are as follows:
|
|
130
|
+
# Admin approval: If a custom whitelist approval process is not set, it will become effective after being approved by the team admins according to the team's decision-making process.
|
|
131
|
+
# Custom whitelist approval: If a whitelist approval process is set, it will become effective after being approved according to the process.
|
|
132
|
+
def create_whitelist(self, request: CreateWhitelistRequest):
|
|
133
|
+
return self.api_client.send_request(request, '/v1/whitelist/create')
|
|
134
|
+
|
|
135
|
+
# Create a Whitelist Based on a Transaction
|
|
136
|
+
# Whitelist the transaction's destination address when the transaction meets the following conditions:
|
|
137
|
+
#
|
|
138
|
+
# A transfer transaction from an asset wallet; Web3 wallet transactions or MPC Sign transactions are not supported.
|
|
139
|
+
# The transaction is in a completed state as COMPLETED.
|
|
140
|
+
# The transaction's destination address is a one-time address.
|
|
141
|
+
def create_from_transaction_whitelist(self, request: CreateFromTransactionWhitelistRequest):
|
|
142
|
+
return self.api_client.send_request(request, '/v1/whitelist/createFromTransaction')
|
|
143
|
+
|
|
144
|
+
# Modify a Whitelist
|
|
145
|
+
# Modify a whitelist based on its unique identifier. The whitelist only supports modifying its name and address; whitelists pending for approval cannot be modified. After modifying the whitelist, it needs to be reviewed and approved in the Safeheron App before it becomes effective. The approval details are as follows:
|
|
146
|
+
# Admin approval: If a custom whitelist approval process is not set, it will become effective after being approved by the team admins according to the team's decision-making process.
|
|
147
|
+
# Custom whitelist approval: If a whitelist approval process is set, it will become effective after being approved according to the process.
|
|
148
|
+
def edit_whitelist(self, request: EditWhitelistRequest):
|
|
149
|
+
return self.api_client.send_request(request, '/v1/whitelist/edit')
|
|
150
|
+
|
|
151
|
+
# Delete a Whitelist
|
|
152
|
+
# To delete a whitelisted address, note that no approval is required for deletion. If a whitelisted address that is under approval is deleted, the approval task will also be automatically cancelled.
|
|
153
|
+
def delete_whitelist(self, request: DeleteWhitelistRequest):
|
|
154
|
+
return self.api_client.send_request(request, '/v1/whitelist/delete')
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
from safeheron_api_sdk_python.tools import *
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class Client:
|
|
5
|
+
|
|
6
|
+
def __init__(self, config):
|
|
7
|
+
self.api_key = config['apiKey']
|
|
8
|
+
self.platform_pub_key = config['safeheronPublicKey']
|
|
9
|
+
self.base_url = config['baseUrl']
|
|
10
|
+
if config.get('requestTimeout'):
|
|
11
|
+
self.requestTimeout = config['requestTimeout'] / 1000
|
|
12
|
+
else:
|
|
13
|
+
self.requestTimeout = 20
|
|
14
|
+
if config.get('privateKey'):
|
|
15
|
+
self.use_private_key = PEM_PRIVATE_HEAD + config['privateKey'] + PEM_PRIVATE_END
|
|
16
|
+
if config.get('privateKeyPemFile'):
|
|
17
|
+
self.use_private_key = load_rsa_private_key(config['privateKeyPemFile'])
|
|
18
|
+
|
|
19
|
+
def send_request(self, request, uri):
|
|
20
|
+
req = encrypt_request(self.api_key, request, self.platform_pub_key, self.use_private_key)
|
|
21
|
+
res = self.execution(req, uri)
|
|
22
|
+
res.raise_for_status()
|
|
23
|
+
res = res.json()
|
|
24
|
+
return decrypt_response(res, self.platform_pub_key, self.use_private_key)
|
|
25
|
+
|
|
26
|
+
def execution(self, request, uri):
|
|
27
|
+
return requests.post(self.base_url + uri, data=json.dumps(request), headers={"Content-Type": "application/json"},
|
|
28
|
+
timeout=self.requestTimeout)
|
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
from safeheron_api_sdk_python.tools import *
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
class CoSignerResponse:
|
|
5
|
+
def __init__(self):
|
|
6
|
+
# approve
|
|
7
|
+
self.approve = None
|
|
8
|
+
# txKey
|
|
9
|
+
self.txKey = None
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class CoSignerResponseV3:
|
|
13
|
+
def __init__(self):
|
|
14
|
+
# action
|
|
15
|
+
self.action = None
|
|
16
|
+
# approvalId
|
|
17
|
+
self.approvalId = None
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
class CoSignerConverter:
|
|
21
|
+
|
|
22
|
+
def __init__(self, config):
|
|
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)
|
|
35
|
+
|
|
36
|
+
def request_convert(self, co_signer_call_back):
|
|
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)
|
|
39
|
+
required_keys = {
|
|
40
|
+
'key',
|
|
41
|
+
'sig',
|
|
42
|
+
'bizContent',
|
|
43
|
+
'timestamp',
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
missing_keys = required_keys.difference(co_signer_call_back.keys())
|
|
47
|
+
if missing_keys:
|
|
48
|
+
raise Exception(co_signer_call_back)
|
|
49
|
+
|
|
50
|
+
# 1 rsa verify
|
|
51
|
+
rsaType = ''
|
|
52
|
+
if "rsaType" in co_signer_call_back:
|
|
53
|
+
rsaType = co_signer_call_back.pop('rsaType')
|
|
54
|
+
|
|
55
|
+
aesType = ''
|
|
56
|
+
if "aesType" in co_signer_call_back:
|
|
57
|
+
aesType = co_signer_call_back.pop('aesType')
|
|
58
|
+
|
|
59
|
+
sig = co_signer_call_back.pop('sig')
|
|
60
|
+
need_sign_message = sort_request(co_signer_call_back)
|
|
61
|
+
v = rsa_verify(platform_rsa_pk, need_sign_message, sig)
|
|
62
|
+
if not v:
|
|
63
|
+
raise Exception("rsa verify: false")
|
|
64
|
+
|
|
65
|
+
# 2 get aes key and iv
|
|
66
|
+
key = co_signer_call_back.pop('key')
|
|
67
|
+
if ECB_OAEP_TYPE == rsaType:
|
|
68
|
+
aes_data = rsa_oaep_decrypt(api_user_rsa_sk, key)
|
|
69
|
+
else:
|
|
70
|
+
aes_data = rsa_decrypt(api_user_rsa_sk, key)
|
|
71
|
+
aes_key = aes_data[0:32]
|
|
72
|
+
aes_iv = aes_data[32:48]
|
|
73
|
+
|
|
74
|
+
# 3 aes decrypt data, get response data
|
|
75
|
+
if GCM_TYPE == aesType:
|
|
76
|
+
r = aes_gcm_decrypt(aes_key, aes_iv, b64decode(co_signer_call_back['bizContent']))
|
|
77
|
+
else:
|
|
78
|
+
r = aes_decrypt(aes_key, aes_iv, b64decode(co_signer_call_back['bizContent']))
|
|
79
|
+
# response_dict['bizContent'] = json.loads(r.decode())
|
|
80
|
+
|
|
81
|
+
return json.loads(r.decode())
|
|
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
|
+
|
|
123
|
+
# It has been Deprecated,Please use convertCoSignerResponseWithNewCryptoType
|
|
124
|
+
def response_converter(self, co_signer_response: CoSignerResponse):
|
|
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)
|
|
127
|
+
|
|
128
|
+
ret = dict()
|
|
129
|
+
|
|
130
|
+
# prepare aes key and iv
|
|
131
|
+
aes_key = get_random_bytes(32)
|
|
132
|
+
aes_iv = get_random_bytes(16)
|
|
133
|
+
response_data = json.dumps(co_signer_response.__dict__).replace('\'', '\"').replace('\n', '').encode('utf-8')
|
|
134
|
+
|
|
135
|
+
# 1 rsa encrypt aes key + iv
|
|
136
|
+
aes_data = aes_key + aes_iv
|
|
137
|
+
ret['key'] = rsa_encrypt(platform_rsa_pk, aes_data)
|
|
138
|
+
|
|
139
|
+
# 2 aes encrypt request data
|
|
140
|
+
if response_data is not None:
|
|
141
|
+
aes_encrypted_bytes = aes_encrypt(aes_key, aes_iv, response_data)
|
|
142
|
+
ret['bizContent'] = b64encode(aes_encrypted_bytes).decode()
|
|
143
|
+
|
|
144
|
+
# 3 set timestamp
|
|
145
|
+
ret['timestamp'] = str(int(time.time() * 1000))
|
|
146
|
+
ret['code'] = str('200')
|
|
147
|
+
ret['message'] = str('SUCCESS')
|
|
148
|
+
|
|
149
|
+
# 4 sign request
|
|
150
|
+
need_sign_message = sort_request(ret)
|
|
151
|
+
ret['sig'] = rsa_sign(api_user_rsa_sk, need_sign_message)
|
|
152
|
+
|
|
153
|
+
return ret
|
|
154
|
+
|
|
155
|
+
def response_converter_with_new_crypto_type(self, co_signer_response: CoSignerResponse):
|
|
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)
|
|
158
|
+
|
|
159
|
+
ret = dict()
|
|
160
|
+
|
|
161
|
+
# prepare aes key and iv
|
|
162
|
+
aes_key = get_random_bytes(32)
|
|
163
|
+
aes_iv = get_random_bytes(16)
|
|
164
|
+
response_data = json.dumps(co_signer_response.__dict__).replace('\'', '\"').replace('\n', '').encode('utf-8')
|
|
165
|
+
|
|
166
|
+
# 1 rsa encrypt aes key + iv
|
|
167
|
+
aes_data = aes_key + aes_iv
|
|
168
|
+
ret['key'] = rsa_oaep_encrypt(platform_rsa_pk, aes_data)
|
|
169
|
+
|
|
170
|
+
# 2 aes encrypt request data
|
|
171
|
+
if response_data is not None:
|
|
172
|
+
aes_encrypted_bytes = aes_gcm_encrypt(aes_key, aes_iv, response_data)
|
|
173
|
+
ret['bizContent'] = b64encode(aes_encrypted_bytes).decode()
|
|
174
|
+
|
|
175
|
+
# 3 set timestamp
|
|
176
|
+
ret['timestamp'] = str(int(time.time() * 1000))
|
|
177
|
+
ret['code'] = str('200')
|
|
178
|
+
ret['message'] = str('SUCCESS')
|
|
179
|
+
|
|
180
|
+
# 4 sign request
|
|
181
|
+
need_sign_message = sort_request(ret)
|
|
182
|
+
ret['sig'] = rsa_sign(api_user_rsa_sk, need_sign_message)
|
|
183
|
+
ret['rsaType'] = ECB_OAEP_TYPE
|
|
184
|
+
ret['aesType'] = GCM_TYPE
|
|
185
|
+
return ret
|