gomyck-tools 1.5.6__py3-none-any.whl → 1.5.7__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.
@@ -16,414 +16,421 @@ from ctools.cipher import sm_util
16
16
 
17
17
 
18
18
  class AuthCodeValidator:
19
- """授权码验证器"""
20
-
21
- def __init__(self, public_key: str = None):
22
- """
23
- 初始化验证器
24
-
25
- Args:
26
- public_key: SM2公钥(用于签名验证)
27
- """
28
- if not public_key:
29
- raise Exception("未提供公钥,无法初始化验证器。请传入 public_key 参数。")
30
- self.public_key = public_key
31
-
32
- def validate(self, authcode_json: str) -> bool:
33
- """
34
- 快速验证授权码是否有效
35
-
36
- Args:
37
- authcode_json: 授权码JSON字符串
38
-
39
- Returns:
40
- bool: 授权码是否有效
41
- """
42
- try:
43
- authcode_obj = json.loads(authcode_json)
44
- except:
45
- return False
46
-
47
- # 验证必需字段
48
- if 'version' not in authcode_obj or 'body' not in authcode_obj or 'signature' not in authcode_obj:
49
- return False
50
-
51
- body = authcode_obj.get('body')
52
- if not isinstance(body, dict):
53
- return False
54
-
55
- return self._verify_signature(authcode_json)
56
-
57
- def _verify_signature(self, authcode_json: str) -> bool:
58
- """
59
- 验证授权码签名
60
-
61
- Args:
62
- authcode_json: 授权码JSON字符串
63
-
64
- Returns:
65
- bool: 签名是否有效
66
- """
67
- if not self.public_key:
68
- raise Exception("未初始化公钥,无法验证签名。请传入 public_key 参数。")
69
-
70
- try:
71
- authcode_obj = json.loads(authcode_json)
72
- body = authcode_obj.get('body', {})
73
- signature = authcode_obj.get('signature', '')
74
- version = authcode_obj.get('version', 'v1_1')
75
-
76
- # 初始化SM2
77
- sm_util.init(self.public_key, self.public_key)
78
-
79
- # 构建签名字符串
80
- final_val = self._build_sign_string(body, version)
81
-
82
- # 验证签名
83
- return sm_util.verify_with_sm2(signature, final_val)
84
- except Exception as e:
85
- try:
86
- # 重试:重新初始化SM2并验证
87
- authcode_obj = json.loads(authcode_json)
88
- body = authcode_obj.get('body', {})
89
- signature = authcode_obj.get('signature', '')
90
- version = authcode_obj.get('version', 'v1_1')
91
-
92
- sm_util.init(self.public_key, self.public_key)
93
- final_val = self._build_sign_string(body, version)
94
- return sm_util.verify_with_sm2(signature, final_val)
95
- except:
96
- return False
97
-
98
- def _build_sign_string(self, body: dict, version: str) -> str:
99
- """
100
- 构建签名字符串,与app.py中的签名逻辑一致
101
-
102
- Args:
103
- body: 授权码内容
104
- version: 版本号
105
-
106
- Returns:
107
- str: 签名字符串
108
- """
109
- ordered_dict = sorted(body.items())
110
- final_val = ""
111
-
112
- for k, v in ordered_dict:
113
- if isinstance(v, list):
114
- value_str = ",".join(v)
115
- else:
116
- value_str = str(v)
117
-
118
- if version == 'v1':
119
- # v1: 不带换行符
120
- final_val += k + ":" + value_str
121
- elif version == 'v1_1':
122
- # v1_1: 带换行符
123
- final_val += k + ":" + value_str + '\n'
124
- else:
125
- # 默认v1_1
126
- final_val += k + ":" + value_str + '\n'
127
-
128
- return final_val
129
-
130
- def check_expired(self, authcode_json: str) -> bool:
131
- """
132
- 检查授权码是否过期
133
-
134
- Args:
135
- authcode_json: 授权码JSON字符串
136
-
137
- Returns:
138
- bool: 是否未过期
139
- """
140
- try:
141
- authcode_obj = json.loads(authcode_json)
142
- body = authcode_obj.get('body', {})
143
-
144
- # 检查过期时间
145
- if 'expired_time' in body:
146
- expired_time_str = body['expired_time']
147
- expired_dt = self._parse_datetime(expired_time_str)
148
-
149
- if not expired_dt:
150
- return False
151
-
152
- if datetime.now() > expired_dt:
153
- return False
154
-
155
- # 检查生效时间
156
- if 'effect_time' in body:
157
- effect_time_str = body['effect_time']
158
- effect_dt = self._parse_datetime(effect_time_str)
159
-
160
- if not effect_dt:
161
- return False
19
+ """授权码验证器"""
20
+
21
+ def __init__(self, public_key: str = None):
22
+ """
23
+ 初始化验证器
24
+
25
+ Args:
26
+ public_key: SM2公钥(用于签名验证)
27
+ """
28
+ if not public_key:
29
+ raise Exception("未提供公钥,无法初始化验证器。请传入 public_key 参数。")
30
+ self.public_key = public_key
31
+
32
+ def validate(self, authcode_json: str) -> bool:
33
+ """
34
+ 快速验证授权码是否有效
35
+
36
+ Args:
37
+ authcode_json: 授权码JSON字符串
38
+
39
+ Returns:
40
+ bool: 授权码是否有效
41
+ """
42
+ try:
43
+ authcode_obj = json.loads(authcode_json)
44
+ except:
45
+ return False
46
+
47
+ # 验证必需字段
48
+ if 'version' not in authcode_obj or 'body' not in authcode_obj or 'signature' not in authcode_obj:
49
+ return False
50
+
51
+ body = authcode_obj.get('body')
52
+ if not isinstance(body, dict):
53
+ return False
54
+
55
+ return self._verify_signature(authcode_json)
56
+
57
+ def _verify_signature(self, authcode_json: str) -> bool:
58
+ """
59
+ 验证授权码签名
60
+
61
+ Args:
62
+ authcode_json: 授权码JSON字符串
63
+
64
+ Returns:
65
+ bool: 签名是否有效
66
+ """
67
+ if not self.public_key:
68
+ raise Exception("未初始化公钥,无法验证签名。请传入 public_key 参数。")
69
+
70
+ try:
71
+ authcode_obj = json.loads(authcode_json)
72
+ body = authcode_obj.get('body', {})
73
+ signature = authcode_obj.get('signature', '')
74
+ version = authcode_obj.get('version', 'v1_1')
75
+
76
+ # 初始化SM2
77
+ sm_util.init(self.public_key, self.public_key)
78
+
79
+ # 构建签名字符串
80
+ final_val = self._build_sign_string(body, version)
81
+
82
+ # 验证签名
83
+ return sm_util.verify_with_sm2(signature, final_val)
84
+ except Exception as e:
85
+ try:
86
+ # 重试:重新初始化SM2并验证
87
+ authcode_obj = json.loads(authcode_json)
88
+ body = authcode_obj.get('body', {})
89
+ signature = authcode_obj.get('signature', '')
90
+ version = authcode_obj.get('version', 'v1_1')
91
+
92
+ sm_util.init(self.public_key, self.public_key)
93
+ final_val = self._build_sign_string(body, version)
94
+ return sm_util.verify_with_sm2(signature, final_val)
95
+ except:
96
+ return False
97
+
98
+ def _build_sign_string(self, body: dict, version: str) -> str:
99
+ """
100
+ 构建签名字符串,与app.py中的签名逻辑一致
101
+
102
+ Args:
103
+ body: 授权码内容
104
+ version: 版本号
105
+
106
+ Returns:
107
+ str: 签名字符串
108
+ """
109
+ ordered_dict = sorted(body.items())
110
+ final_val = ""
111
+
112
+ for k, v in ordered_dict:
113
+ if isinstance(v, list):
114
+ value_str = ",".join(v)
115
+ else:
116
+ value_str = str(v)
117
+
118
+ if version == 'v1':
119
+ # v1: 不带换行符
120
+ final_val += k + ":" + value_str
121
+ elif version == 'v1_1':
122
+ # v1_1: 带换行符
123
+ final_val += k + ":" + value_str + '\n'
124
+ else:
125
+ # 默认v1_1
126
+ final_val += k + ":" + value_str + '\n'
127
+
128
+ return final_val
129
+
130
+ def check_expired(self, authcode_json: str) -> bool:
131
+ """
132
+ 检查授权码是否过期
133
+
134
+ Args:
135
+ authcode_json: 授权码JSON字符串
136
+
137
+ Returns:
138
+ bool: 是否未过期
139
+ """
140
+ try:
141
+ authcode_obj = json.loads(authcode_json)
142
+ body = authcode_obj.get('body', {})
143
+
144
+ # 检查过期时间
145
+ if 'expired_time' in body:
146
+ expired_time_str = body['expired_time']
147
+ expired_dt = self._parse_datetime(expired_time_str)
148
+
149
+ if not expired_dt:
150
+ return False
151
+
152
+ if datetime.now() > expired_dt:
153
+ return False
154
+
155
+ # 检查生效时间
156
+ if 'effect_time' in body:
157
+ effect_time_str = body['effect_time']
158
+ effect_dt = self._parse_datetime(effect_time_str)
159
+
160
+ if not effect_dt:
161
+ return False
162
+
163
+ if datetime.now() < effect_dt:
164
+ return False
165
+
166
+ return True
167
+ except:
168
+ return False
169
+
170
+ def check_ip(self, authcode_json: str, client_ip: str) -> bool:
171
+ """
172
+ 检查客户端IP是否在授权范围内
173
+
174
+ Args:
175
+ authcode_json: 授权码JSON字符串
176
+ client_ip: 客户端IP地址
177
+
178
+ Returns:
179
+ bool: IP是否在授权范围内
180
+ """
181
+ try:
182
+ authcode_obj = json.loads(authcode_json)
183
+ body = authcode_obj.get('body', {})
184
+
185
+ if 'ip_range' not in body:
186
+ return True
162
187
 
163
- if datetime.now() < effect_dt:
164
- return False
188
+ ip_ranges = body['ip_range']
189
+ if not ip_ranges:
190
+ return False
165
191
 
166
- return True
167
- except:
168
- return False
192
+ # 转换为列表
193
+ if isinstance(ip_ranges, str):
194
+ ip_list = [ip.strip() for ip in ip_ranges.split(',')]
195
+ elif isinstance(ip_ranges, list):
196
+ ip_list = ip_ranges
197
+ else:
198
+ return False
169
199
 
170
- def check_ip(self, authcode_json: str, client_ip: str) -> bool:
171
- """
172
- 检查客户端IP是否在授权范围内
200
+ # 支持通配符 "*"
201
+ if '*' in ip_list:
202
+ return True
173
203
 
174
- Args:
175
- authcode_json: 授权码JSON字符串
176
- client_ip: 客户端IP地址
204
+ # 检查IP是否在范围内
205
+ try:
206
+ client_ip_obj = ipaddress.ip_address(client_ip)
207
+ except:
208
+ return False
177
209
 
178
- Returns:
179
- bool: IP是否在授权范围内
180
- """
210
+ for ip_pattern in ip_list:
181
211
  try:
182
- authcode_obj = json.loads(authcode_json)
183
- body = authcode_obj.get('body', {})
184
-
185
- if 'ip_range' not in body:
186
- return True
187
-
188
- ip_ranges = body['ip_range']
189
- if not ip_ranges:
190
- return False
191
-
192
- # 转换为列表
193
- if isinstance(ip_ranges, str):
194
- ip_list = [ip.strip() for ip in ip_ranges.split(',')]
195
- elif isinstance(ip_ranges, list):
196
- ip_list = ip_ranges
197
- else:
198
- return False
199
-
200
- # 支持通配符 "*"
201
- if '*' in ip_list:
202
- return True
203
-
204
- # 检查IP是否在范围内
205
- try:
206
- client_ip_obj = ipaddress.ip_address(client_ip)
207
- except:
208
- return False
209
-
210
- for ip_pattern in ip_list:
211
- try:
212
- if '/' in ip_pattern:
213
- # CIDR格式
214
- ip_network = ipaddress.ip_network(ip_pattern, strict=False)
215
- if client_ip_obj in ip_network:
216
- return True
217
- else:
218
- # 精确匹配
219
- if str(client_ip_obj) == ip_pattern:
220
- return True
221
- except:
222
- continue
223
-
224
- return False
212
+ if '/' in ip_pattern:
213
+ # CIDR格式
214
+ ip_network = ipaddress.ip_network(ip_pattern, strict=False)
215
+ if client_ip_obj in ip_network:
216
+ return True
217
+ else:
218
+ # 精确匹配
219
+ if str(client_ip_obj) == ip_pattern:
220
+ return True
225
221
  except:
226
- return False
227
-
228
- def check_machine_code(self, authcode_json: str, machine_code: str) -> bool:
229
- """
230
- 检查机器码是否被授权
222
+ continue
231
223
 
232
- Args:
233
- authcode_json: 授权码JSON字符串
234
- machine_code: 机器码
224
+ return False
225
+ except:
226
+ return False
235
227
 
236
- Returns:
237
- bool: 机器码是否被授权
238
- """
239
- try:
240
- authcode_obj = json.loads(authcode_json)
241
- body = authcode_obj.get('body', {})
228
+ def check_machine_code(self, authcode_json: str, machine_code: str) -> bool:
229
+ """
230
+ 检查机器码是否被授权
242
231
 
243
- if 'machine_codes' not in body:
244
- return True
232
+ Args:
233
+ authcode_json: 授权码JSON字符串
234
+ machine_code: 机器码
245
235
 
246
- codes = body['machine_codes']
247
- if not codes:
248
- return False
236
+ Returns:
237
+ bool: 机器码是否被授权
238
+ """
239
+ try:
240
+ authcode_obj = json.loads(authcode_json)
241
+ body = authcode_obj.get('body', {})
249
242
 
250
- # 转换为列表
251
- if isinstance(codes, str):
252
- code_list = [c.strip() for c in codes.split(',')]
253
- elif isinstance(codes, list):
254
- code_list = codes
255
- else:
256
- return False
243
+ if 'machine_codes' not in body:
244
+ return True
257
245
 
258
- # 支持通配符 "*"
259
- if '*' in code_list:
260
- return True
246
+ codes = body['machine_codes']
247
+ if not codes:
248
+ return False
261
249
 
262
- return machine_code in code_list
263
- except:
264
- return False
250
+ # 转换为列表
251
+ if isinstance(codes, str):
252
+ code_list = [c.strip() for c in codes.split(',')]
253
+ elif isinstance(codes, list):
254
+ code_list = codes
255
+ else:
256
+ return False
265
257
 
266
- def check_module(self, authcode_json: str, module_name: str) -> bool:
267
- """
268
- 检查模块是否被授权
258
+ # 支持通配符 "*"
259
+ if '*' in code_list:
260
+ return True
269
261
 
270
- Args:
271
- authcode_json: 授权码JSON字符串
272
- module_name: 模块名称
262
+ return machine_code in code_list
263
+ except:
264
+ return False
273
265
 
274
- Returns:
275
- bool: 模块是否被授权
276
- """
277
- try:
278
- authcode_obj = json.loads(authcode_json)
279
- body = authcode_obj.get('body', {})
266
+ def check_module(self, authcode_json: str, module_name: str) -> bool:
267
+ """
268
+ 检查模块是否被授权
280
269
 
281
- if 'modules' not in body:
282
- return True
270
+ Args:
271
+ authcode_json: 授权码JSON字符串
272
+ module_name: 模块名称
283
273
 
284
- modules = body['modules']
285
- if not modules:
286
- return False
274
+ Returns:
275
+ bool: 模块是否被授权
276
+ """
277
+ try:
278
+ authcode_obj = json.loads(authcode_json)
279
+ body = authcode_obj.get('body', {})
287
280
 
288
- # 转换为列表
289
- if isinstance(modules, str):
290
- module_list = [m.strip() for m in modules.split(',')]
291
- elif isinstance(modules, list):
292
- module_list = modules
293
- else:
294
- return False
281
+ if 'modules' not in body:
282
+ return True
295
283
 
296
- # 支持通配符 "*"
297
- if '*' in module_list:
298
- return True
284
+ modules = body['modules']
285
+ if not modules:
286
+ return False
299
287
 
300
- return module_name in module_list
301
- except:
302
- return False
288
+ # 转换为列表
289
+ if isinstance(modules, str):
290
+ module_list = [m.strip() for m in modules.split(',')]
291
+ elif isinstance(modules, list):
292
+ module_list = modules
293
+ else:
294
+ return False
303
295
 
304
- def check_artifact(self, authcode_json: str, artifact_name: str) -> bool:
305
- """
306
- 检查制品名称是否匹配
296
+ # 支持通配符 "*"
297
+ if '*' in module_list:
298
+ return True
307
299
 
308
- Args:
309
- authcode_json: 授权码JSON字符串
310
- artifact_name: 制品名称
300
+ return module_name in module_list
301
+ except:
302
+ return False
311
303
 
312
- Returns:
313
- bool: 制品是否被授权
314
- """
315
- try:
316
- authcode_obj = json.loads(authcode_json)
317
- body = authcode_obj.get('body', {})
304
+ def check_artifact(self, authcode_json: str, artifact_name: str) -> bool:
305
+ """
306
+ 检查制品名称是否匹配
318
307
 
319
- if 'artifact' not in body:
320
- return True
308
+ Args:
309
+ authcode_json: 授权码JSON字符串
310
+ artifact_name: 制品名称
321
311
 
322
- authorized_artifact = body['artifact']
312
+ Returns:
313
+ bool: 制品是否被授权
314
+ """
315
+ try:
316
+ authcode_obj = json.loads(authcode_json)
317
+ body = authcode_obj.get('body', {})
323
318
 
324
- # 支持通配符 "*"
325
- if authorized_artifact == '*':
326
- return True
319
+ if 'artifact' not in body:
320
+ return True
327
321
 
328
- return artifact_name == authorized_artifact
329
- except:
330
- return False
322
+ authorized_artifact = body['artifact']
331
323
 
332
- def check_version(self, authcode_json: str, version: str) -> bool:
333
- """
334
- 检查版本是否被授权
324
+ # 支持通配符 "*"
325
+ if authorized_artifact == '*':
326
+ return True
335
327
 
336
- Args:
337
- authcode_json: 授权码JSON字符串
338
- version: 版本号
328
+ return artifact_name == authorized_artifact
329
+ except:
330
+ return False
339
331
 
340
- Returns:
341
- bool: 版本是否被授权
342
- """
343
- try:
344
- authcode_obj = json.loads(authcode_json)
345
- body = authcode_obj.get('body', {})
332
+ def check_version(self, authcode_json: str, version: str) -> bool:
333
+ """
334
+ 检查版本是否被授权
346
335
 
347
- if 'version' not in body:
348
- return True
336
+ Args:
337
+ authcode_json: 授权码JSON字符串
338
+ version: 版本号
349
339
 
350
- authorized_version = body['version']
340
+ Returns:
341
+ bool: 版本是否被授权
342
+ """
343
+ try:
344
+ authcode_obj = json.loads(authcode_json)
345
+ body = authcode_obj.get('body', {})
351
346
 
352
- # 支持通配符 "*"
353
- if authorized_version == '*':
354
- return True
347
+ if 'version' not in body:
348
+ return True
355
349
 
356
- return version == authorized_version
357
- except:
358
- return False
359
-
360
- def validate_all(self, authcode_json: str, client_ip: str = None,
361
- machine_code: str = None, artifact: str = None,
362
- version: str = None, module: str = None) -> bool:
363
- """
364
- 检查所有条件是否都满足
365
-
366
- Args:
367
- authcode_json: 授权码JSON字符串
368
- client_ip: 客户端IP(可选)
369
- machine_code: 机器码(可选)
370
- artifact: 制品名称(可选)
371
- version: 版本号(可选)
372
- module: 模块名称(可选)
373
-
374
- Returns:
375
- bool: 所有条件是否都满足
376
- """
377
- # 基本验证
378
- if not self.validate(authcode_json):
379
- return False
380
-
381
- # 检查时间
382
- if not self.check_expired(authcode_json):
383
- return False
384
-
385
- # 检查IP
386
- if client_ip and not self.check_ip(authcode_json, client_ip):
387
- return False
388
-
389
- # 检查机器码
390
- if machine_code and not self.check_machine_code(authcode_json, machine_code):
391
- return False
392
-
393
- # 检查制品
394
- if artifact and not self.check_artifact(authcode_json, artifact):
395
- return False
396
-
397
- # 检查版本
398
- if version and not self.check_version(authcode_json, version):
399
- return False
400
-
401
- # 检查模块
402
- if module and not self.check_module(authcode_json, module):
403
- return False
350
+ authorized_version = body['version']
404
351
 
352
+ # 支持通配符 "*"
353
+ if authorized_version == '*':
405
354
  return True
406
355
 
407
- # ============= 私有方法 =============
408
-
409
- def _parse_datetime(self, date_str: str) -> Optional[datetime]:
410
- """解析日期时间字符串"""
411
- if not date_str:
412
- return None
413
-
414
- # 尝试多种格式
415
- formats = [
416
- '%Y-%m-%dT%H:%M', # ISO: 2026-01-26T09:23
417
- '%Y-%m-%dT%H:%M:%S', # ISO: 2026-01-26T09:23:45
418
- '%Y-%m-%d %H:%M:%S', # 标准: 2026-01-26 09:23:45
419
- '%Y-%m-%d %H:%M', # 标准: 2026-01-26 09:23
420
- '%Y-%m-%d', # 日期: 2026-01-26
421
- ]
422
-
423
- for fmt in formats:
424
- try:
425
- return datetime.strptime(date_str, fmt)
426
- except:
427
- continue
428
-
429
- return None
356
+ return version == authorized_version
357
+ except:
358
+ return False
359
+
360
+ def validate_all(self, authcode_json: str, client_ip: str = None,
361
+ machine_code: str = None, artifact: str = None,
362
+ version: str = None, module: str = None) -> bool:
363
+ """
364
+ 检查所有条件是否都满足
365
+
366
+ Args:
367
+ authcode_json: 授权码JSON字符串
368
+ client_ip: 客户端IP(可选)
369
+ machine_code: 机器码(可选)
370
+ artifact: 制品名称(可选)
371
+ version: 版本号(可选)
372
+ module: 模块名称(可选)
373
+
374
+ Returns:
375
+ bool: 所有条件是否都满足
376
+ """
377
+ # 基本验证
378
+ if not self.validate(authcode_json):
379
+ print('基本验证失败')
380
+ return False
381
+
382
+ # 检查时间
383
+ if not self.check_expired(authcode_json):
384
+ print('时间验证失败')
385
+ return False
386
+
387
+ # 检查IP
388
+ if client_ip and not self.check_ip(authcode_json, client_ip):
389
+ print('IP验证失败')
390
+ return False
391
+
392
+ # 检查机器码
393
+ if machine_code and not self.check_machine_code(authcode_json, machine_code):
394
+ print('机器码验证失败')
395
+ return False
396
+
397
+ # 检查制品
398
+ if artifact and not self.check_artifact(authcode_json, artifact):
399
+ print('制品名称验证失败')
400
+ return False
401
+
402
+ # 检查版本
403
+ if version and not self.check_version(authcode_json, version):
404
+ print('版本验证失败')
405
+ return False
406
+
407
+ # 检查模块
408
+ if module and not self.check_module(authcode_json, module):
409
+ print('模块验证失败')
410
+ return False
411
+
412
+ return True
413
+
414
+ # ============= 私有方法 =============
415
+
416
+ def _parse_datetime(self, date_str: str) -> Optional[datetime]:
417
+ """解析日期时间字符串"""
418
+ if not date_str:
419
+ return None
420
+
421
+ # 尝试多种格式
422
+ formats = [
423
+ '%Y-%m-%dT%H:%M', # ISO: 2026-01-26T09:23
424
+ '%Y-%m-%dT%H:%M:%S', # ISO: 2026-01-26T09:23:45
425
+ '%Y-%m-%d %H:%M:%S', # 标准: 2026-01-26 09:23:45
426
+ '%Y-%m-%d %H:%M', # 标准: 2026-01-26 09:23
427
+ '%Y-%m-%d', # 日期: 2026-01-26
428
+ ]
429
+
430
+ for fmt in formats:
431
+ try:
432
+ return datetime.strptime(date_str, fmt)
433
+ except:
434
+ continue
435
+
436
+ return None