huaweicloud-encryption-sdk-python 1.2.1__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.
Files changed (174) hide show
  1. examples/file_encryption_example.py +57 -0
  2. examples/key_capsule_encryption_example.py +240 -0
  3. examples/kms_discovery_encryption_example.py +56 -0
  4. examples/local_aes_encryption_example.py +59 -0
  5. examples/test_rsa.py +42 -0
  6. examples/test_sm2.py +38 -0
  7. examples/test_sm4_cbc.py +37 -0
  8. examples/test_sm4_gcm.py +37 -0
  9. huaweicloud_encryption_sdk_python-1.2.1.dist-info/METADATA +18 -0
  10. huaweicloud_encryption_sdk_python-1.2.1.dist-info/RECORD +174 -0
  11. huaweicloud_encryption_sdk_python-1.2.1.dist-info/WHEEL +5 -0
  12. huaweicloud_encryption_sdk_python-1.2.1.dist-info/top_level.txt +3 -0
  13. huaweicloud_encryptionsdk/__init__.py +5 -0
  14. huaweicloud_encryptionsdk/_apig_sdk/__init__.py +1 -0
  15. huaweicloud_encryptionsdk/_apig_sdk/signer.py +278 -0
  16. huaweicloud_encryptionsdk/_apig_sdk/signer_v11.py +70 -0
  17. huaweicloud_encryptionsdk/_apig_sdk/sm3_hash.py +141 -0
  18. huaweicloud_encryptionsdk/_lts_sdk/auth/__init__.py +0 -0
  19. huaweicloud_encryptionsdk/_lts_sdk/auth/signer.py +174 -0
  20. huaweicloud_encryptionsdk/_lts_sdk/consumer/__init__.py +0 -0
  21. huaweicloud_encryptionsdk/_lts_sdk/consumer/client/__init__.py +0 -0
  22. huaweicloud_encryptionsdk/_lts_sdk/consumer/client/consumer_client_adapter.py +59 -0
  23. huaweicloud_encryptionsdk/_lts_sdk/consumer/client/http_client.py +211 -0
  24. huaweicloud_encryptionsdk/_lts_sdk/consumer/core/__init__.py +0 -0
  25. huaweicloud_encryptionsdk/_lts_sdk/consumer/core/client_consumer_worker.py +106 -0
  26. huaweicloud_encryptionsdk/_lts_sdk/consumer/core/consumer_heartbeat.py +73 -0
  27. huaweicloud_encryptionsdk/_lts_sdk/consumer/core/log_shard_consumer.py +179 -0
  28. huaweicloud_encryptionsdk/_lts_sdk/consumer/interface/__init__.py +0 -0
  29. huaweicloud_encryptionsdk/_lts_sdk/consumer/interface/consumer_check_point_tracker.py +120 -0
  30. huaweicloud_encryptionsdk/_lts_sdk/consumer/interface/consumer_processor.py +18 -0
  31. huaweicloud_encryptionsdk/_lts_sdk/consumer/interface/consumer_processor_factory.py +3 -0
  32. huaweicloud_encryptionsdk/_lts_sdk/consumer/model/__init__.py +0 -0
  33. huaweicloud_encryptionsdk/_lts_sdk/consumer/model/check_point.py +20 -0
  34. huaweicloud_encryptionsdk/_lts_sdk/consumer/model/consumer_config.py +27 -0
  35. huaweicloud_encryptionsdk/_lts_sdk/consumer/model/log_data.py +18 -0
  36. huaweicloud_encryptionsdk/_lts_sdk/consumer/model/task_result.py +40 -0
  37. huaweicloud_encryptionsdk/_lts_sdk/consumer/task/__init__.py +0 -0
  38. huaweicloud_encryptionsdk/_lts_sdk/consumer/task/consumer_fetch_task.py +53 -0
  39. huaweicloud_encryptionsdk/_lts_sdk/consumer/task/initial_task.py +55 -0
  40. huaweicloud_encryptionsdk/_lts_sdk/consumer/task/process_task.py +25 -0
  41. huaweicloud_encryptionsdk/_lts_sdk/consumer/task/shutdown_task.py +24 -0
  42. huaweicloud_encryptionsdk/_lts_sdk/consumer_main.py +88 -0
  43. huaweicloud_encryptionsdk/_lts_sdk/parallel_main.py +64 -0
  44. huaweicloud_encryptionsdk/_lts_sdk/producer/__init__.py +0 -0
  45. huaweicloud_encryptionsdk/_lts_sdk/producer/callback/__init__.py +0 -0
  46. huaweicloud_encryptionsdk/_lts_sdk/producer/callback/call_back.py +7 -0
  47. huaweicloud_encryptionsdk/_lts_sdk/producer/core/__init__.py +0 -0
  48. huaweicloud_encryptionsdk/_lts_sdk/producer/core/accumulator.py +135 -0
  49. huaweicloud_encryptionsdk/_lts_sdk/producer/core/io_thread_pool.py +107 -0
  50. huaweicloud_encryptionsdk/_lts_sdk/producer/core/io_worker.py +124 -0
  51. huaweicloud_encryptionsdk/_lts_sdk/producer/core/mover.py +69 -0
  52. huaweicloud_encryptionsdk/_lts_sdk/producer/core/producer.py +98 -0
  53. huaweicloud_encryptionsdk/_lts_sdk/producer/lts_http/__init__.py +0 -0
  54. huaweicloud_encryptionsdk/_lts_sdk/producer/lts_http/http_client.py +63 -0
  55. huaweicloud_encryptionsdk/_lts_sdk/producer/lts_http/simple_request.py +14 -0
  56. huaweicloud_encryptionsdk/_lts_sdk/producer/model/__init__.py +0 -0
  57. huaweicloud_encryptionsdk/_lts_sdk/producer/model/config.py +50 -0
  58. huaweicloud_encryptionsdk/_lts_sdk/producer/model/error.py +18 -0
  59. huaweicloud_encryptionsdk/_lts_sdk/producer/model/log.py +87 -0
  60. huaweicloud_encryptionsdk/_lts_sdk/producer/model/log_batch.py +154 -0
  61. huaweicloud_encryptionsdk/_lts_sdk/producer/model/lts_store.py +21 -0
  62. huaweicloud_encryptionsdk/_lts_sdk/producer/model/result.py +17 -0
  63. huaweicloud_encryptionsdk/_lts_sdk/producer/model/retry_queue.py +39 -0
  64. huaweicloud_encryptionsdk/_lts_sdk/serial_main.py +77 -0
  65. huaweicloud_encryptionsdk/_lts_sdk/utils/__init__.py +0 -0
  66. huaweicloud_encryptionsdk/_lts_sdk/utils/common.py +57 -0
  67. huaweicloud_encryptionsdk/_lts_sdk/utils/lts_threading.py +32 -0
  68. huaweicloud_encryptionsdk/cache/__init__.py +0 -0
  69. huaweicloud_encryptionsdk/cache/data_key_cache.py +79 -0
  70. huaweicloud_encryptionsdk/cache/local_data_key_cache.py +161 -0
  71. huaweicloud_encryptionsdk/common/__init__.py +0 -0
  72. huaweicloud_encryptionsdk/common/constants.py +15 -0
  73. huaweicloud_encryptionsdk/common/counting_output_stream.py +18 -0
  74. huaweicloud_encryptionsdk/common/crypto_factory.py +48 -0
  75. huaweicloud_encryptionsdk/common/ec_private_key_loader.py +43 -0
  76. huaweicloud_encryptionsdk/common/ecs_metadata_service.py +42 -0
  77. huaweicloud_encryptionsdk/common/file_path_for_example_constants.py +4 -0
  78. huaweicloud_encryptionsdk/common/utils.py +162 -0
  79. huaweicloud_encryptionsdk/exception/__init__.py +0 -0
  80. huaweicloud_encryptionsdk/exception/errors.py +109 -0
  81. huaweicloud_encryptionsdk/handler/__init__.py +0 -0
  82. huaweicloud_encryptionsdk/handler/cipher_handler.py +294 -0
  83. huaweicloud_encryptionsdk/handler/crypto_handler.py +24 -0
  84. huaweicloud_encryptionsdk/handler/default_crypto_handler.py +148 -0
  85. huaweicloud_encryptionsdk/handler/default_serialize_handler.py +45 -0
  86. huaweicloud_encryptionsdk/handler/file_decrypt_handler.py +101 -0
  87. huaweicloud_encryptionsdk/handler/file_encrypt_handler.py +30 -0
  88. huaweicloud_encryptionsdk/handler/serialize_handler.py +14 -0
  89. huaweicloud_encryptionsdk/huawei_config.py +49 -0
  90. huaweicloud_encryptionsdk/huawei_crypto.py +311 -0
  91. huaweicloud_encryptionsdk/keyrings/__init__.py +0 -0
  92. huaweicloud_encryptionsdk/keyrings/keyring.py +14 -0
  93. huaweicloud_encryptionsdk/keyrings/keyring_factory.py +10 -0
  94. huaweicloud_encryptionsdk/keyrings/kms_keyring_factory.py +21 -0
  95. huaweicloud_encryptionsdk/keyrings/kmskeyring/__init__.py +0 -0
  96. huaweicloud_encryptionsdk/keyrings/kmskeyring/kms_discovery_keyring.py +51 -0
  97. huaweicloud_encryptionsdk/keyrings/kmskeyring/kms_key_capsule_keyring.py +100 -0
  98. huaweicloud_encryptionsdk/keyrings/kmskeyring/kms_keyring.py +155 -0
  99. huaweicloud_encryptionsdk/keyrings/kmskeyring/kms_multi_region_keyring.py +8 -0
  100. huaweicloud_encryptionsdk/keyrings/raw_keyring_factory.py +27 -0
  101. huaweicloud_encryptionsdk/keyrings/rawkeyring/__init__.py +0 -0
  102. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_aes_keyring.py +63 -0
  103. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_keyring.py +112 -0
  104. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_rsa_keyring.py +55 -0
  105. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_sm2_keyring.py +75 -0
  106. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_sm4_cbc_keyring.py +66 -0
  107. huaweicloud_encryptionsdk/keyrings/rawkeyring/raw_sm4_keyring.py +70 -0
  108. huaweicloud_encryptionsdk/kms/__init__.py +0 -0
  109. huaweicloud_encryptionsdk/kms/create_key_capsule_request.py +35 -0
  110. huaweicloud_encryptionsdk/kms/create_key_capsule_response.py +19 -0
  111. huaweicloud_encryptionsdk/kms/decrypt_key_capsule_request.py +32 -0
  112. huaweicloud_encryptionsdk/kms/decrypt_key_capsule_response.py +19 -0
  113. huaweicloud_encryptionsdk/kms/kms_http_client.py +116 -0
  114. huaweicloud_encryptionsdk/log/__init__.py +0 -0
  115. huaweicloud_encryptionsdk/log/log_config.py +30 -0
  116. huaweicloud_encryptionsdk/log/log_file_backup.py +144 -0
  117. huaweicloud_encryptionsdk/log/log_metrics.py +132 -0
  118. huaweicloud_encryptionsdk/log/log_reporter_manager.py +163 -0
  119. huaweicloud_encryptionsdk/log/lts_sdk_producer.py +386 -0
  120. huaweicloud_encryptionsdk/log/lts_struct_log_builder.py +106 -0
  121. huaweicloud_encryptionsdk/meterialmanager/__init__.py +0 -0
  122. huaweicloud_encryptionsdk/meterialmanager/cache_crypto_meterial_manager.py +221 -0
  123. huaweicloud_encryptionsdk/meterialmanager/crypto_meterial_manager.py +19 -0
  124. huaweicloud_encryptionsdk/meterialmanager/data_key_generate.py +10 -0
  125. huaweicloud_encryptionsdk/meterialmanager/data_key_generate_factory.py +20 -0
  126. huaweicloud_encryptionsdk/meterialmanager/default_crypto_meterials_manager.py +71 -0
  127. huaweicloud_encryptionsdk/meterialmanager/key_capsule_data_key_generate.py +63 -0
  128. huaweicloud_encryptionsdk/meterialmanager/kms_data_key_generate.py +65 -0
  129. huaweicloud_encryptionsdk/meterialmanager/local_data_key_generate.py +13 -0
  130. huaweicloud_encryptionsdk/model/__init__.py +0 -0
  131. huaweicloud_encryptionsdk/model/access_point_config.py +9 -0
  132. huaweicloud_encryptionsdk/model/cipher_body.py +81 -0
  133. huaweicloud_encryptionsdk/model/cipher_header.py +405 -0
  134. huaweicloud_encryptionsdk/model/ciphertext_data_key.py +166 -0
  135. huaweicloud_encryptionsdk/model/crypto_result.py +11 -0
  136. huaweicloud_encryptionsdk/model/data_key_materials.py +17 -0
  137. huaweicloud_encryptionsdk/model/data_materials.py +11 -0
  138. huaweicloud_encryptionsdk/model/enums/__init__.py +0 -0
  139. huaweicloud_encryptionsdk/model/enums/access_point_type.py +28 -0
  140. huaweicloud_encryptionsdk/model/enums/crypto_algorithm.py +75 -0
  141. huaweicloud_encryptionsdk/model/enums/data_key_generate_type.py +20 -0
  142. huaweicloud_encryptionsdk/model/enums/key_provider_enum.py +19 -0
  143. huaweicloud_encryptionsdk/model/enums/keyring_type_enum.py +27 -0
  144. huaweicloud_encryptionsdk/model/key_capsule.py +10 -0
  145. huaweicloud_encryptionsdk/model/key_capsule_config.py +12 -0
  146. huaweicloud_encryptionsdk/model/kms_config.py +10 -0
  147. huaweicloud_encryptionsdk/model/request/__init__.py +0 -0
  148. huaweicloud_encryptionsdk/model/request/encrypt_request.py +10 -0
  149. huaweicloud_encryptionsdk/model/request/sign_request.py +2 -0
  150. huaweicloud_encryptionsdk/model/request/verify_request.py +2 -0
  151. huaweicloud_encryptionsdk/proof/__init__.py +0 -0
  152. huaweicloud_encryptionsdk/proof/attestation_document.py +36 -0
  153. huaweicloud_encryptionsdk/proof/collector/__init__.py +0 -0
  154. huaweicloud_encryptionsdk/proof/collector/cce_proof_collector.py +24 -0
  155. huaweicloud_encryptionsdk/proof/collector/ecs_proof_collector.py +11 -0
  156. huaweicloud_encryptionsdk/proof/collector/key_pair_proof_collector.py +55 -0
  157. huaweicloud_encryptionsdk/proof/collector/ma_proof_collector.py +51 -0
  158. huaweicloud_encryptionsdk/proof/private_key_decrypt_callback.py +7 -0
  159. huaweicloud_encryptionsdk/proof/proof_collector.py +11 -0
  160. huaweicloud_encryptionsdk/proof/proof_collector_factory.py +53 -0
  161. huaweicloud_encryptionsdk/proof/proof_info.py +10 -0
  162. huaweicloud_encryptionsdk/util/__init__.py +0 -0
  163. huaweicloud_encryptionsdk/util/common_utils.py +12 -0
  164. tests/__init__.py +0 -0
  165. tests/test_enums.py +84 -0
  166. tests/test_exceptions.py +38 -0
  167. tests/test_factories.py +71 -0
  168. tests/test_huawei_crypto.py +67 -0
  169. tests/test_imports.py +46 -0
  170. tests/test_kms_models.py +95 -0
  171. tests/test_log_file_backup.py +45 -0
  172. tests/test_lts_struct_log_builder.py +97 -0
  173. tests/test_models.py +142 -0
  174. tests/test_utils.py +111 -0
@@ -0,0 +1,141 @@
1
+ #
2
+ # Copyright (c) Huawei Technologies Co., Ltd. 2025. All rights reserved.
3
+ #
4
+ # coding=utf-8
5
+
6
+ import hashlib
7
+ from sys import version_info
8
+
9
+ if version_info.major == 3:
10
+ if version_info.minor < 7:
11
+ _IV = [0x7380166f, 0x4914b2b9, 0x172442d7, 0xda8a0600, 0xa96f30bc, 0x163138aa, 0xe38dee4d, 0xb0fb0e4e]
12
+ _T_J = [0x79cc4519 if j < 16 else 0x7a879d8a for j in range(64)]
13
+ _0X8F = 0xffffffff
14
+
15
+ _OUT_OF_RANGE_ERROR = ValueError("j out of range [0, 64)")
16
+
17
+
18
+ def _left_rotate(n, k):
19
+ # type: (int, int) -> int
20
+ """
21
+ Shift the binary representation of n to the left by k bits,
22
+ and then shift the k bits of the highest bits to the lowest bits to form a new 32-bit unsigned integer.
23
+ """
24
+ return ((n << k) & _0X8F) | ((n >> (32 - k)) & _0X8F)
25
+
26
+
27
+ def _ff_j(x, y, z, j):
28
+ # type: (int, int, int, int) -> int
29
+ """Boolean function, take different expressions as j changes. Based on GB/T 32905-2016."""
30
+ if 0 <= j < 16:
31
+ return x ^ y ^ z
32
+ elif 16 <= j < 64:
33
+ return (x & y) | (x & z) | (y & z)
34
+ else:
35
+ raise _OUT_OF_RANGE_ERROR
36
+
37
+
38
+ def _gg_j(x, y, z, j):
39
+ # type: (int, int, int, int) -> int
40
+ """Boolean function, take different expressions as j changes, based on GB/T 32905-2016."""
41
+ if 0 <= j < 16:
42
+ return x ^ y ^ z
43
+ elif 16 <= j < 64:
44
+ return (x & y) ^ (~x & z)
45
+ else:
46
+ raise _OUT_OF_RANGE_ERROR
47
+
48
+
49
+ def _p_0(x):
50
+ # type: (int) -> int
51
+ """permutation function in compression function, based on GB/T 32905-2016."""
52
+ return x ^ _left_rotate(x, 9) ^ _left_rotate(x, 17)
53
+
54
+
55
+ def _p_1(x):
56
+ # type: (int) -> int
57
+ """permutation function in compression function, based on GB/T 32905-2016."""
58
+ return x ^ _left_rotate(x, 15) ^ _left_rotate(x, 23)
59
+
60
+
61
+ def _cf(v_i, b_i):
62
+ # type: (list[int], list[int]) -> list[int]
63
+ """Compression function, based on GB/T 32905-2016."""
64
+ w = [0] * 68
65
+ for i in range(16):
66
+ data = b_i[i * 4: (i + 1) * 4]
67
+ w[i] = int.from_bytes(data, byteorder='big')
68
+
69
+ for i in range(16, 68):
70
+ w[i] = _p_1(w[i - 16] ^ w[i - 9] ^ (_left_rotate(w[i - 3], 15))) ^ (_left_rotate(w[i - 13], 7)) ^ w[
71
+ i - 6]
72
+
73
+ w_1 = [w[i] ^ w[i + 4] for i in range(64)]
74
+
75
+ a, b, c, d, e, f, g, h = v_i
76
+
77
+ for i in range(64):
78
+ ss_1 = _left_rotate((_left_rotate(a, 12) + e + _left_rotate(_T_J[i], i % 32)) & _0X8F, 7)
79
+ ss_2 = ss_1 ^ _left_rotate(a, 12)
80
+ tt_1 = (_ff_j(a, b, c, i) + d + ss_2 + w_1[i]) & _0X8F
81
+ tt_2 = (_gg_j(e, f, g, i) + h + ss_1 + w[i]) & _0X8F
82
+ d, c, b, a, h, g, f, e = c, _left_rotate(b, 9), a, tt_1, g, _left_rotate(f, 19), e, _p_0(tt_2)
83
+ a, b, c, d, e, f, g, h = map(lambda x: x & _0X8F, (a, b, c, d, e, f, g, h))
84
+
85
+ v_j = (a, b, c, d, e, f, g, h)
86
+ return [v_j[i] ^ v_i[i] for i in range(8)]
87
+
88
+
89
+ def _hash(data):
90
+ # type: (bytes) -> bytes
91
+ """Hash function, based on GB/T 32905-2016."""
92
+ data_list = [i for i in data]
93
+ length = len(data_list)
94
+ bit_length = length * 8
95
+ k = (56 - length - 1) % 64
96
+ data_list.append(0x80)
97
+ data_list.extend([0x00] * k)
98
+ data_list.extend([i for i in bit_length.to_bytes(8, 'big')])
99
+
100
+ iter_count = int(len(data_list) / 64)
101
+ b = [data_list[i * 64:(i + 1) * 64] for i in range(iter_count)]
102
+
103
+ v = [_IV]
104
+
105
+ i = 0
106
+ for i in range(iter_count):
107
+ v.append(_cf(v[i], b[i]))
108
+
109
+ return b''.join(map(lambda n: n.to_bytes(4, 'big'), v[i + 1]))
110
+
111
+
112
+ class _SM3Hash:
113
+ name = 'sm3'
114
+ digest_size = 32
115
+ block_size = 64
116
+
117
+ def __init__(self, data=b''):
118
+ self._bytearray = bytearray(data)
119
+
120
+ def update(self, data):
121
+ # type: (bytes) -> None
122
+ self._bytearray.extend(data)
123
+
124
+ def digest(self):
125
+ # type: () -> bytes
126
+ return _hash(bytes(self._bytearray))
127
+
128
+ def hexdigest(self):
129
+ # type: () -> str
130
+ return self.digest().hex()
131
+
132
+ def copy(self):
133
+ # type: () -> _SM3Hash
134
+ return self.__class__(bytes(self._bytearray))
135
+
136
+
137
+ new_sm3_hash = lambda data=b'': _SM3Hash(data)
138
+ else:
139
+ new_sm3_hash = lambda data=b'': hashlib.new('sm3', data)
140
+ else:
141
+ new_sm3_hash = None
File without changes
@@ -0,0 +1,174 @@
1
+ import datetime
2
+ import hashlib
3
+ import hmac
4
+ from typing import List
5
+ from urllib.parse import unquote, quote
6
+
7
+ import requests
8
+ from huaweicloud_encryptionsdk._lts_sdk.producer.lts_http.simple_request import LtsRequest
9
+
10
+
11
+ class Constants:
12
+ HEADER_X_DATA = "X-Sdk-Date"
13
+ BASIC_DATE_FORMAT = "%Y%m%dT%H%M%SZ"
14
+ DERIVED_DATE_FORMAT = "%Y%m%d"
15
+ HEADER_CONTENT_SHA256 = "X-Sdk-Content-Sha256"
16
+ AUTH_SERVICE_NAME = "lts"
17
+ ALGORITHM = "V11-HMAC-SHA256"
18
+ HEADER_AUTHORIZATION = "Authorization"
19
+
20
+
21
+ class Signer(object):
22
+
23
+ def __init__(self):
24
+ self._hash_func = hashlib.sha256
25
+
26
+ def _derive_key(self, ak, sk, info):
27
+ salt = bytearray(ak, 'utf-8')
28
+ ikm = bytearray(sk, 'utf-8')
29
+ info_bytes = bytearray(info, 'utf-8')
30
+ prk = hmac.new(salt, ikm, self._hash_func).digest()
31
+ okm = b""
32
+ t = b""
33
+ for i in range(1, (32 + 32) // 32 + 1):
34
+ t = hmac.new(prk, t + info_bytes + bytes([i]), self._hash_func).digest()
35
+ okm += t
36
+ return okm[:32].hex()
37
+
38
+ def sign(self, lts_request: LtsRequest) -> requests.Request:
39
+ try:
40
+ if lts_request.method not in {"POST", "PATCH", "PUT"}:
41
+ lts_request.body = ""
42
+
43
+ if lts_request.security_token:
44
+ lts_request.headers["X-Security-Token"] = lts_request.security_token
45
+
46
+ date_time = datetime.datetime.now(datetime.timezone.utc)
47
+ if Constants.HEADER_X_DATA not in lts_request.headers:
48
+ lts_request.headers[Constants.HEADER_X_DATA] = date_time.strftime(Constants.BASIC_DATE_FORMAT)
49
+ else:
50
+ time = lts_request.headers[Constants.HEADER_X_DATA]
51
+ date_time = datetime.datetime.strptime(time, Constants.BASIC_DATE_FORMAT)
52
+
53
+ signed_headers = self._signed_headers(lts_request)
54
+ canonical_request = self._canonical_request(lts_request, signed_headers)
55
+ date_str = datetime.datetime.strftime(date_time, Constants.DERIVED_DATE_FORMAT)
56
+ info_str = "%s/%s/%s" % (date_str, lts_request.region, Constants.AUTH_SERVICE_NAME)
57
+ string_to_sign = self._string_to_sign_derived(canonical_request, date_time, info_str)
58
+ derivation_key = self._derive_key(lts_request.ak, lts_request.sk, info_str)
59
+ signature = self._sign_string_to_sign(string_to_sign, derivation_key)
60
+ auth_value = self._derivation_auth_header_value(signature, lts_request.ak, signed_headers, info_str)
61
+ lts_request.headers[Constants.HEADER_AUTHORIZATION] = auth_value
62
+
63
+ url = lts_request.host + lts_request.interface
64
+ req = requests.Request(method=lts_request.method, headers=lts_request.headers, data=lts_request.body,
65
+ url=url, params=lts_request.query)
66
+ return req
67
+ except Exception as e:
68
+ pass
69
+
70
+ def _hash_hex_string(self, data):
71
+ # type: (bytes) -> str
72
+ _hash = self._hash_func(data)
73
+ return _hash.hexdigest()
74
+
75
+ @classmethod
76
+ def _signed_headers(cls, lts_request: LtsRequest):
77
+ key_list = []
78
+ for key, value in lts_request.headers.items():
79
+ key_list.append(key.lower())
80
+ key_list.sort()
81
+ return key_list
82
+
83
+ @classmethod
84
+ def _canonical_headers(cls, request: LtsRequest, signed_headers: List[str]):
85
+ canonical_headers = []
86
+ __headers = {}
87
+ for key in request.headers:
88
+ key_encoded = key.lower()
89
+ value = request.headers[key]
90
+ value_encoded = str(value).strip()
91
+ __headers[key_encoded] = value_encoded
92
+
93
+ for key in signed_headers:
94
+ canonical_headers.append(key + ":" + __headers.get(key))
95
+
96
+ return '\n'.join(canonical_headers) + "\n"
97
+
98
+ @classmethod
99
+ def _canonical_uri(cls, lts_request: LtsRequest):
100
+ pattens = unquote(lts_request.interface).split("/")
101
+ uri = []
102
+ for v in pattens:
103
+ uri.append(cls._url_encode(v))
104
+ url_path = "/".join(uri)
105
+
106
+ if url_path[-1] != '/':
107
+ url_path = url_path + "/"
108
+
109
+ return url_path
110
+
111
+ @classmethod
112
+ def _url_encode(cls, s):
113
+ return quote(s, safe='~')
114
+
115
+ @classmethod
116
+ def _canonical_query_string(cls, lts_request: LtsRequest):
117
+ query_keys = []
118
+ for key, value in lts_request.query.items():
119
+ query_keys.append(key)
120
+ query_keys.sort()
121
+ canonical_query_param = []
122
+
123
+ for query_key in query_keys:
124
+ encode_query_key = cls._url_encode(query_key)
125
+ query_value = lts_request.query[query_key]
126
+ if isinstance(query_value, str):
127
+ kv = "%s=%s" % (encode_query_key, cls._url_encode(query_value))
128
+ canonical_query_param.append(kv)
129
+ elif isinstance(query_value, bool):
130
+ kv = "%s=%s" % (encode_query_key, cls._url_encode(str(query_value).lower()))
131
+ canonical_query_param.append(kv)
132
+ elif isinstance(query_value, int):
133
+ kv = "%s=%s" % (encode_query_key, cls._url_encode(str(query_value)))
134
+ canonical_query_param.append(kv)
135
+ return '&'.join(canonical_query_param)
136
+
137
+ def _canonical_request(self, lts_request: LtsRequest, signed_headers: List[str]):
138
+ hex_encode = ""
139
+ if Constants.HEADER_CONTENT_SHA256 in signed_headers:
140
+ hex_encode = lts_request.headers[Constants.HEADER_CONTENT_SHA256]
141
+ else:
142
+ hex_encode = self._hash_hex_string(lts_request.body.encode('utf-8'))
143
+
144
+ canonical_uri = self._canonical_uri(lts_request)
145
+ canonical_query_string = self._canonical_query_string(lts_request)
146
+ canonical_headers = self._canonical_headers(lts_request, signed_headers)
147
+
148
+ return "{0}\n{1}\n{2}\n{3}\n{4}\n{5}".format(lts_request.method.upper(), canonical_uri, canonical_query_string,
149
+ canonical_headers,
150
+ ";".join(signed_headers), hex_encode)
151
+
152
+ def _string_to_sign_derived(self, canonical_request, time, info=None):
153
+ # type: (str, datetime, str) -> str
154
+ return "%s\n%s\n%s\n%s" % (
155
+ Constants.ALGORITHM,
156
+ datetime.datetime.strftime(time, Constants.DERIVED_DATE_FORMAT),
157
+ info,
158
+ self._hash_hex_string(canonical_request.encode('utf-8')))
159
+
160
+ def _sign_string_to_sign(self, string_to_sign, key):
161
+ # type: (str, str) -> str
162
+ return self._hex(self._hmac(key.encode('utf-8'), string_to_sign.encode('utf-8')))
163
+
164
+ def _derivation_auth_header_value(self, signature, app_key, signed_headers, info=None):
165
+ # type: (str, str, list, str) -> str
166
+ return "%s Credential=%s/%s, SignedHeaders=%s, Signature=%s" % (
167
+ Constants.ALGORITHM, app_key, info, ";".join(signed_headers), signature)
168
+
169
+ def _hex(self, data):
170
+ return data.hex()
171
+
172
+ def _hmac(self, key, data):
173
+ # type: (bytes, bytes) -> bytes
174
+ return hmac.new(key, data, digestmod=self._hash_func).digest()
@@ -0,0 +1,59 @@
1
+ from consumer.client.http_client import HttpClient
2
+ from consumer.model.consumer_config import ConsumerConfig
3
+ from huaweicloud_encryptionsdk._lts_sdk.utils import lts_threading
4
+
5
+
6
+ class LogConsumerClientAdapter(object):
7
+ def __init__(self, config: ConsumerConfig):
8
+ self._project_id = config.project_id
9
+ self._log_group_id = config.log_group_id
10
+ self._log_stream_id = config.log_stream_id
11
+ self._region_name = config.region_name
12
+ self._consumer_group_name = config.consumer_group_name
13
+ self._consumer = config.consumer
14
+ self._is_shutdown = False
15
+ self._client = HttpClient(config)
16
+ self._lock = lts_threading.ReadWriteLock()
17
+
18
+ def shutdown(self):
19
+ self._is_shutdown = True
20
+
21
+ def hear_beat(self, all_shards):
22
+ self._lock.acquire_read()
23
+ try:
24
+ return self._client.heart_beat(self._project_id, self._log_group_id, self._log_stream_id,
25
+ self._consumer_group_name, self._consumer, all_shards)
26
+ finally:
27
+ self._lock.release_read()
28
+
29
+ def fetch_consumer_group(self, shard_id):
30
+ self._lock.acquire_read()
31
+ try:
32
+ return self._client.fetch_consumer_group(self._project_id, self._log_group_id, self._log_stream_id,
33
+ self._consumer_group_name, shard_id)
34
+ finally:
35
+ self._lock.release_read()
36
+
37
+ def update_check_point(self, shard_id, consumer, check_point):
38
+ self._lock.acquire_read()
39
+ try:
40
+ return self._client.update_check_point(self._project_id, self._log_group_id, self._log_stream_id,
41
+ self._consumer_group_name, shard_id, consumer, check_point)
42
+ finally:
43
+ self._lock.release_read()
44
+
45
+ def batch_get_logs(self, shard_id, batch_size, start_time, end_time):
46
+ self._lock.acquire_read()
47
+ try:
48
+ return self._client.batch_get_log(self._project_id, self._log_group_id, self._log_stream_id, shard_id,
49
+ batch_size, start_time, end_time)
50
+ finally:
51
+ self._lock.release_read()
52
+
53
+ def get_cursor_by_time(self, shard_id, time):
54
+ self._lock.acquire_read()
55
+ try:
56
+ return self._client.get_cursor_by_time(self._project_id, self._log_group_id, self._log_stream_id, shard_id,
57
+ time)
58
+ finally:
59
+ self._lock.release_read()
@@ -0,0 +1,211 @@
1
+ import json
2
+ from json import JSONDecodeError
3
+
4
+ import requests
5
+ import urllib3
6
+ from loguru import logger
7
+ from requests.adapters import HTTPAdapter
8
+ from urllib3.exceptions import InsecureRequestWarning
9
+ from urllib3.util.retry import Retry
10
+
11
+ from huaweicloud_encryptionsdk._lts_sdk.auth.signer import Signer
12
+ from consumer.model.check_point import ShardCheckPoint, Cursor
13
+ from consumer.model.consumer_config import ConsumerConfig
14
+ from consumer.model.log_data import BatchGetLog
15
+ from huaweicloud_encryptionsdk._lts_sdk.producer.lts_http.simple_request import LtsRequest
16
+ from huaweicloud_encryptionsdk._lts_sdk.producer.model import error
17
+ from huaweicloud_encryptionsdk._lts_sdk.utils import common
18
+
19
+
20
+ class HttpClient(object):
21
+ def __init__(self, config: ConsumerConfig):
22
+ self._session = requests.Session()
23
+ self._signer = Signer()
24
+ self._config = config
25
+
26
+ retry_strategy = Retry(
27
+ total=2,
28
+ status_forcelist=[429, 500, 502, 503, 504],
29
+ backoff_factor=1
30
+ )
31
+ adapter = HTTPAdapter(max_retries=retry_strategy, pool_connections=100, pool_maxsize=100)
32
+ self._session.mount("https://", adapter)
33
+ self._session.mount("http://", adapter)
34
+ urllib3.disable_warnings(InsecureRequestWarning)
35
+
36
+ @staticmethod
37
+ def connect_query_string(query_map, url):
38
+ if query_map is None or len(query_map) == 0:
39
+ return url
40
+ query_list = []
41
+ for key, value in query_map.items():
42
+ query_list.append(key + "=" + value)
43
+
44
+ query_url = "&".join(query_list)
45
+ return url + "?" + query_url
46
+
47
+ def heart_beat(self, project_id, log_group_id, log_stream_id, consumer_group_name, consumer, all_shards):
48
+ interface = f"/v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/consumer-groups/{consumer_group_name}/heartbeat"
49
+ query_map = {"consumer_name": consumer}
50
+ body = common.convert_obj2_json_str(all_shards)
51
+ r = self.generate_request("POST", interface, query_map, body, self._config)
52
+ try:
53
+ begin_time = common.current_time_ms()
54
+ response = self._session.send(r, verify=False)
55
+ response.encoding = "utf-8"
56
+ end_time = common.current_time_ms()
57
+ logger.debug("httpclient url is {}, code is {}, body is {}, result is {}, cost [{}]ms", r.url,
58
+ response.status_code,
59
+ body,
60
+ response.content.decode("utf-8"),
61
+ end_time - begin_time)
62
+ if response.status_code == 200:
63
+ result_str = response.content.decode("utf-8")
64
+ try:
65
+ result = json.loads(result_str)
66
+ except JSONDecodeError as e:
67
+ logger.info("heart beat result is not json: {}", result_str)
68
+ return error.Error(error_code=error.RESULT_JSON_FORMAT_ERROR_CODE,
69
+ error_msg=result_str,
70
+ http_code=response.status_code), None
71
+ return None, result
72
+ else:
73
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=response.content.decode("utf-8"),
74
+ http_code=response.status_code), None
75
+ except Exception as e:
76
+ logger.error("httpclient url is {}, exception is {}", r.url, str(e))
77
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=str(e), http_code=0), None
78
+
79
+ def fetch_consumer_group(self, project_id, log_group_id, log_stream_id, consumer_group_name, shard_id):
80
+ interface = f"/v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/consumer-groups/{consumer_group_name}"
81
+ query_map = None
82
+ if len(shard_id) > 0:
83
+ query_map = {"shard_id": shard_id}
84
+ r = self.generate_request("GET", interface, query_map, "", self._config)
85
+ try:
86
+ begin_time = common.current_time_ms()
87
+ response = self._session.send(r, verify=False)
88
+ end_time = common.current_time_ms()
89
+ response.encoding = "utf-8"
90
+ logger.debug("httpclient url is {}, code is {}, result is {}, cost [{}]ms", r.url, response.status_code,
91
+ response.content.decode("utf-8"), end_time - begin_time)
92
+ if response.status_code == 200:
93
+ result_str = response.content.decode("utf-8")
94
+ try:
95
+ result = common.convert_json_str2_list_obj(result_str, ShardCheckPoint)
96
+ except JSONDecodeError as e:
97
+ logger.error("fetch_consumer_group result is not json: {}", result_str)
98
+ return error.Error(error_code=error.RESULT_JSON_FORMAT_ERROR_CODE,
99
+ error_msg=result_str,
100
+ http_code=response.status_code), None
101
+ return None, result
102
+ else:
103
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=response.content.decode("utf-8"),
104
+ http_code=response.status_code), None
105
+ except Exception as e:
106
+ logger.error("httpclient url is {}, exception is {}", r.url, str(e))
107
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=str(e), http_code=0), None
108
+
109
+ def get_cursor_by_time(self, project_id, log_group_id, log_stream_id, shard_id, time):
110
+ interface = f"/v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/shards/{shard_id}/cursor"
111
+ query_map = {"from": time}
112
+ r = self.generate_request("GET", interface, query_map, "", self._config)
113
+ try:
114
+ begin_time = common.current_time_ms()
115
+ response = self._session.send(r, verify=False)
116
+ end_time = common.current_time_ms()
117
+ response.encoding = "utf-8"
118
+ logger.info("httpclient url is {}, code is {}, result is {}, cost [{}]ms", r.url, response.status_code,
119
+ response.content.decode("utf-8"), end_time - begin_time)
120
+ if response.status_code == 200:
121
+ result_str = response.content.decode("utf-8")
122
+ try:
123
+ result = common.convert_json_str2_obj(result_str, Cursor)
124
+ except JSONDecodeError as e:
125
+ logger.error("get_cursor_by_time result is not json: {}", result_str)
126
+ return error.Error(error_code=error.RESULT_JSON_FORMAT_ERROR_CODE,
127
+ error_msg=result_str,
128
+ http_code=response.status_code), None
129
+ return None, result
130
+ else:
131
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=response.content.decode("utf-8"),
132
+ http_code=response.status_code), None
133
+ except Exception as e:
134
+ logger.error("httpclient url is {}, exception is {}", r.url, str(e))
135
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=str(e), http_code=0), None
136
+
137
+ def update_check_point(self, project_id, log_group_id, log_stream_id, consumer_group_name, shard_id, consumer,
138
+ check_point):
139
+ interface = f"/v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/consumer-groups/{consumer_group_name}"
140
+ query_map = {"consumer_name": consumer}
141
+ request_body = []
142
+ param = {"shard_id": shard_id, "checkpoint": check_point}
143
+ request_body.append(param)
144
+ logger.debug("update check point, shard_id {}, checkpoint {} request_body is {}", shard_id, check_point,
145
+ request_body)
146
+ body = common.convert_obj2_json_str(request_body)
147
+ r = self.generate_request("POST", interface, query_map, body, self._config)
148
+ try:
149
+ begin_time = common.current_time_ms()
150
+ response = self._session.send(r, verify=False)
151
+ end_time = common.current_time_ms()
152
+ response.encoding = "utf-8"
153
+ logger.debug("httpclient url is {}, code is {}, body is {}, result is {}, cost [{}]ms", r.url,
154
+ response.status_code,
155
+ body,
156
+ response.content.decode("utf-8"), end_time - begin_time)
157
+ if response.status_code == 200:
158
+ return None
159
+ else:
160
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=response.content.decode("utf-8"),
161
+ http_code=response.status_code)
162
+ except Exception as e:
163
+ logger.error("httpclient url is {}, exception is {}", r.url, str(e))
164
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=str(e), http_code=0)
165
+
166
+ def batch_get_log(self, project_id, log_group_id, log_stream_id, shard_id, batch_size, start_time, end_time):
167
+ interface = f"/v2/{project_id}/groups/{log_group_id}/streams/{log_stream_id}/shards/{shard_id}"
168
+ query_map = {"limit": batch_size, "start": start_time}
169
+ if len(end_time) > 0:
170
+ query_map["end"] = end_time
171
+ r = self.generate_request("GET", interface, query_map, "", self._config)
172
+ try:
173
+ begin_time = common.current_time_ms()
174
+ response = self._session.send(r, verify=False)
175
+ end_time = common.current_time_ms()
176
+ response.encoding = "utf-8"
177
+ logger.debug("httpclient url is {} query map is {}, code is {}, result is {}, cost [{}]ms", r.url,
178
+ query_map,
179
+ response.status_code,
180
+ response.content.decode("utf-8"), end_time - begin_time)
181
+ if response.status_code == 200:
182
+ result_str = response.content.decode("utf-8")
183
+ try:
184
+ result = common.convert_json_str2_obj(result_str, BatchGetLog)
185
+ except JSONDecodeError as e:
186
+ logger.error("batch_get_log result is not json: {}", result_str)
187
+ return error.Error(error_code=error.RESULT_JSON_FORMAT_ERROR_CODE,
188
+ error_msg=result_str,
189
+ http_code=response.status_code), None
190
+ return None, result
191
+ else:
192
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=response.content.decode("utf-8"),
193
+ http_code=response.status_code), None
194
+ except Exception as e:
195
+ logger.error("httpclient url is {}, exception is {}", r.url, str(e))
196
+ return error.Error(error_code=error.HTTP_QUEST_ERROR_CODE, error_msg=str(e), http_code=0), None
197
+
198
+ def generate_request(self, method, interface, query_map, body, config):
199
+ header = {"content-type": "application/json"}
200
+ if query_map is None:
201
+ req = LtsRequest(method=method, host=config.endpoint, headers=header, body=body, region=config.region_name,
202
+ interface=interface, ak=config.access_key, sk=config.access_secret)
203
+ request = self._signer.sign(req)
204
+ r = request.prepare()
205
+ return r
206
+ else:
207
+ req = LtsRequest(method=method, host=config.endpoint, headers=header, body=body, region=config.region_name,
208
+ interface=interface, ak=config.access_key, sk=config.access_secret, **query_map)
209
+ request = self._signer.sign(req)
210
+ r = request.prepare()
211
+ return r