gomyck-tools 1.5.5__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.
- ctools/authcode_validator.py +379 -372
- ctools/ml/__init__.py +4 -0
- ctools/ml/interface/__init__.py +4 -0
- ctools/ml/interface/image_processor.py +42 -0
- ctools/ml/model_loader.py +36 -0
- ctools/util/file_crypto.py +92 -0
- {gomyck_tools-1.5.5.dist-info → gomyck_tools-1.5.7.dist-info}/METADATA +5 -4
- {gomyck_tools-1.5.5.dist-info → gomyck_tools-1.5.7.dist-info}/RECORD +11 -9
- ctools/ml/image_process.py +0 -121
- ctools/ml/img_extractor.py +0 -59
- ctools/ml/ppi.py +0 -276
- {gomyck_tools-1.5.5.dist-info → gomyck_tools-1.5.7.dist-info}/WHEEL +0 -0
- {gomyck_tools-1.5.5.dist-info → gomyck_tools-1.5.7.dist-info}/licenses/LICENSE +0 -0
- {gomyck_tools-1.5.5.dist-info → gomyck_tools-1.5.7.dist-info}/top_level.txt +0 -0
ctools/authcode_validator.py
CHANGED
|
@@ -16,414 +16,421 @@ from ctools.cipher import sm_util
|
|
|
16
16
|
|
|
17
17
|
|
|
18
18
|
class AuthCodeValidator:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
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
|
-
|
|
164
|
-
|
|
188
|
+
ip_ranges = body['ip_range']
|
|
189
|
+
if not ip_ranges:
|
|
190
|
+
return False
|
|
165
191
|
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
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
|
-
|
|
171
|
-
|
|
172
|
-
|
|
200
|
+
# 支持通配符 "*"
|
|
201
|
+
if '*' in ip_list:
|
|
202
|
+
return True
|
|
173
203
|
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
204
|
+
# 检查IP是否在范围内
|
|
205
|
+
try:
|
|
206
|
+
client_ip_obj = ipaddress.ip_address(client_ip)
|
|
207
|
+
except:
|
|
208
|
+
return False
|
|
177
209
|
|
|
178
|
-
|
|
179
|
-
bool: IP是否在授权范围内
|
|
180
|
-
"""
|
|
210
|
+
for ip_pattern in ip_list:
|
|
181
211
|
try:
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
if
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
if
|
|
190
|
-
|
|
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
|
-
|
|
227
|
-
|
|
228
|
-
def check_machine_code(self, authcode_json: str, machine_code: str) -> bool:
|
|
229
|
-
"""
|
|
230
|
-
检查机器码是否被授权
|
|
222
|
+
continue
|
|
231
223
|
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
224
|
+
return False
|
|
225
|
+
except:
|
|
226
|
+
return False
|
|
235
227
|
|
|
236
|
-
|
|
237
|
-
|
|
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
|
-
|
|
244
|
-
|
|
232
|
+
Args:
|
|
233
|
+
authcode_json: 授权码JSON字符串
|
|
234
|
+
machine_code: 机器码
|
|
245
235
|
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
236
|
+
Returns:
|
|
237
|
+
bool: 机器码是否被授权
|
|
238
|
+
"""
|
|
239
|
+
try:
|
|
240
|
+
authcode_obj = json.loads(authcode_json)
|
|
241
|
+
body = authcode_obj.get('body', {})
|
|
249
242
|
|
|
250
|
-
|
|
251
|
-
|
|
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
|
-
|
|
260
|
-
|
|
246
|
+
codes = body['machine_codes']
|
|
247
|
+
if not codes:
|
|
248
|
+
return False
|
|
261
249
|
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
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
|
-
|
|
267
|
-
|
|
268
|
-
|
|
258
|
+
# 支持通配符 "*"
|
|
259
|
+
if '*' in code_list:
|
|
260
|
+
return True
|
|
269
261
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
262
|
+
return machine_code in code_list
|
|
263
|
+
except:
|
|
264
|
+
return False
|
|
273
265
|
|
|
274
|
-
|
|
275
|
-
|
|
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
|
-
|
|
282
|
-
|
|
270
|
+
Args:
|
|
271
|
+
authcode_json: 授权码JSON字符串
|
|
272
|
+
module_name: 模块名称
|
|
283
273
|
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
274
|
+
Returns:
|
|
275
|
+
bool: 模块是否被授权
|
|
276
|
+
"""
|
|
277
|
+
try:
|
|
278
|
+
authcode_obj = json.loads(authcode_json)
|
|
279
|
+
body = authcode_obj.get('body', {})
|
|
287
280
|
|
|
288
|
-
|
|
289
|
-
|
|
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
|
-
|
|
298
|
-
|
|
284
|
+
modules = body['modules']
|
|
285
|
+
if not modules:
|
|
286
|
+
return False
|
|
299
287
|
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
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
|
-
|
|
305
|
-
|
|
306
|
-
|
|
296
|
+
# 支持通配符 "*"
|
|
297
|
+
if '*' in module_list:
|
|
298
|
+
return True
|
|
307
299
|
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
300
|
+
return module_name in module_list
|
|
301
|
+
except:
|
|
302
|
+
return False
|
|
311
303
|
|
|
312
|
-
|
|
313
|
-
|
|
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
|
-
|
|
320
|
-
|
|
308
|
+
Args:
|
|
309
|
+
authcode_json: 授权码JSON字符串
|
|
310
|
+
artifact_name: 制品名称
|
|
321
311
|
|
|
322
|
-
|
|
312
|
+
Returns:
|
|
313
|
+
bool: 制品是否被授权
|
|
314
|
+
"""
|
|
315
|
+
try:
|
|
316
|
+
authcode_obj = json.loads(authcode_json)
|
|
317
|
+
body = authcode_obj.get('body', {})
|
|
323
318
|
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
return True
|
|
319
|
+
if 'artifact' not in body:
|
|
320
|
+
return True
|
|
327
321
|
|
|
328
|
-
|
|
329
|
-
except:
|
|
330
|
-
return False
|
|
322
|
+
authorized_artifact = body['artifact']
|
|
331
323
|
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
324
|
+
# 支持通配符 "*"
|
|
325
|
+
if authorized_artifact == '*':
|
|
326
|
+
return True
|
|
335
327
|
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
328
|
+
return artifact_name == authorized_artifact
|
|
329
|
+
except:
|
|
330
|
+
return False
|
|
339
331
|
|
|
340
|
-
|
|
341
|
-
|
|
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
|
-
|
|
348
|
-
|
|
336
|
+
Args:
|
|
337
|
+
authcode_json: 授权码JSON字符串
|
|
338
|
+
version: 版本号
|
|
349
339
|
|
|
350
|
-
|
|
340
|
+
Returns:
|
|
341
|
+
bool: 版本是否被授权
|
|
342
|
+
"""
|
|
343
|
+
try:
|
|
344
|
+
authcode_obj = json.loads(authcode_json)
|
|
345
|
+
body = authcode_obj.get('body', {})
|
|
351
346
|
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
return True
|
|
347
|
+
if 'version' not in body:
|
|
348
|
+
return True
|
|
355
349
|
|
|
356
|
-
|
|
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
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
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
|