ezKit 1.12.0__py3-none-any.whl → 1.12.2__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.
- ezKit/bottle_extensions.py +8 -4
- ezKit/cipher.py +19 -16
- ezKit/database.py +15 -25
- ezKit/dockerhub.py +9 -3
- ezKit/http.py +9 -6
- ezKit/mongo.py +3 -2
- ezKit/qywx.py +34 -24
- ezKit/redis.py +2 -1
- ezKit/sendemail.py +12 -4
- ezKit/token.py +13 -13
- ezKit/utils.py +136 -294
- ezKit/xftp.py +39 -17
- ezKit/zabbix.py +140 -101
- {ezkit-1.12.0.dist-info → ezkit-1.12.2.dist-info}/METADATA +1 -1
- ezkit-1.12.2.dist-info/RECORD +22 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.2.dist-info}/WHEEL +1 -1
- ezkit-1.12.0.dist-info/RECORD +0 -22
- {ezkit-1.12.0.dist-info → ezkit-1.12.2.dist-info}/licenses/LICENSE +0 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.2.dist-info}/top_level.txt +0 -0
ezKit/bottle_extensions.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
"""Bottle Extensions"""
|
2
|
+
|
2
3
|
from types import FunctionType
|
3
4
|
from typing import Any
|
4
5
|
|
@@ -7,20 +8,23 @@ from . import bottle, utils
|
|
7
8
|
|
8
9
|
def enable_cors(fn: FunctionType) -> Any | None:
|
9
10
|
"""Bottle CORS"""
|
11
|
+
|
10
12
|
# 参考文档:
|
11
13
|
# - https://stackoverflow.com/a/17262900
|
12
14
|
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Headers
|
13
15
|
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Methods
|
14
16
|
# - https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Access-Control-Allow-Origin
|
15
17
|
def cors(*args, **kwargs):
|
16
|
-
bottle.response.headers[
|
17
|
-
bottle.response.headers[
|
18
|
-
bottle.response.headers[
|
19
|
-
if bottle.request.method !=
|
18
|
+
bottle.response.headers["Access-Control-Allow-Headers"] = "*"
|
19
|
+
bottle.response.headers["Access-Control-Allow-Methods"] = "*"
|
20
|
+
bottle.response.headers["Access-Control-Allow-Origin"] = "*"
|
21
|
+
if bottle.request.method != "OPTIONS":
|
20
22
|
return fn(*args, **kwargs)
|
21
23
|
return None
|
24
|
+
|
22
25
|
return cors
|
23
26
|
|
27
|
+
|
24
28
|
def request_json() -> bottle.DictProperty | None:
|
25
29
|
"""Bottle Request JSON"""
|
26
30
|
try:
|
ezKit/cipher.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""Cipher"""
|
1
|
+
"""Cipher Library"""
|
2
|
+
|
2
3
|
# https://docs.python.org/3.10/library/hashlib.html
|
3
4
|
# https://www.pycrypto.org/
|
4
5
|
# https://stackoverflow.com/a/21928790
|
@@ -14,31 +15,31 @@ from loguru import logger
|
|
14
15
|
class AESCipher:
|
15
16
|
"""AESCipher"""
|
16
17
|
|
17
|
-
def __init__(self, key: str =
|
18
|
+
def __init__(self, key: str = "vB7DoRm9C2Kd", algorithm: str = "sha256"):
|
18
19
|
|
19
20
|
self.bs = AES.block_size
|
20
21
|
|
21
22
|
# dir(hashlib)
|
22
23
|
match True:
|
23
|
-
case True if algorithm ==
|
24
|
+
case True if algorithm == "md5":
|
24
25
|
self.key = hashlib.md5(key.encode()).digest()
|
25
|
-
case True if algorithm ==
|
26
|
+
case True if algorithm == "sha1":
|
26
27
|
self.key = hashlib.sha1(key.encode()).digest()
|
27
|
-
case True if algorithm ==
|
28
|
+
case True if algorithm == "sha224":
|
28
29
|
self.key = hashlib.sha224(key.encode()).digest()
|
29
|
-
case True if algorithm ==
|
30
|
+
case True if algorithm == "sha256":
|
30
31
|
self.key = hashlib.sha256(key.encode()).digest()
|
31
|
-
case True if algorithm ==
|
32
|
+
case True if algorithm == "sha384":
|
32
33
|
self.key = hashlib.sha384(key.encode()).digest()
|
33
|
-
case True if algorithm ==
|
34
|
+
case True if algorithm == "sha512":
|
34
35
|
self.key = hashlib.sha512(key.encode()).digest()
|
35
|
-
case True if algorithm ==
|
36
|
+
case True if algorithm == "sha3_224":
|
36
37
|
self.key = hashlib.sha3_224(key.encode()).digest()
|
37
|
-
case True if algorithm ==
|
38
|
+
case True if algorithm == "sha3_256":
|
38
39
|
self.key = hashlib.sha3_256(key.encode()).digest()
|
39
|
-
case True if algorithm ==
|
40
|
+
case True if algorithm == "sha3_384":
|
40
41
|
self.key = hashlib.sha3_384(key.encode()).digest()
|
41
|
-
case True if algorithm ==
|
42
|
+
case True if algorithm == "sha3_512":
|
42
43
|
self.key = hashlib.sha3_512(key.encode()).digest()
|
43
44
|
# case True if algorithm == 'shake_128':
|
44
45
|
# self.key = hashlib.shake_128(key.encode()).digest()
|
@@ -52,7 +53,7 @@ class AESCipher:
|
|
52
53
|
raw = self._pad(raw)
|
53
54
|
iv = Random.new().read(AES.block_size)
|
54
55
|
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
55
|
-
return base64.b64encode(iv + cipher.encrypt(raw.encode())).decode(
|
56
|
+
return base64.b64encode(iv + cipher.encrypt(raw.encode())).decode("utf-8")
|
56
57
|
except Exception as e:
|
57
58
|
logger.exception(e)
|
58
59
|
return None
|
@@ -60,9 +61,11 @@ class AESCipher:
|
|
60
61
|
def decrypt(self, enc: str) -> str | None:
|
61
62
|
try:
|
62
63
|
enc_bytes = base64.b64decode(enc)
|
63
|
-
iv = enc_bytes[:AES.block_size]
|
64
|
+
iv = enc_bytes[: AES.block_size]
|
64
65
|
cipher = AES.new(self.key, AES.MODE_CBC, iv)
|
65
|
-
return self._unpad(cipher.decrypt(enc_bytes[AES.block_size:])).decode(
|
66
|
+
return self._unpad(cipher.decrypt(enc_bytes[AES.block_size :])).decode(
|
67
|
+
"utf-8"
|
68
|
+
)
|
66
69
|
except Exception as e:
|
67
70
|
logger.exception(e)
|
68
71
|
return None
|
@@ -72,4 +75,4 @@ class AESCipher:
|
|
72
75
|
|
73
76
|
@staticmethod
|
74
77
|
def _unpad(s: bytes) -> bytes:
|
75
|
-
return s[
|
78
|
+
return s[: -ord(s[len(s) - 1 :])]
|
ezKit/database.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""Database"""
|
1
|
+
"""Database Library"""
|
2
|
+
|
2
3
|
# Column, Table, MetaData API
|
3
4
|
# https://docs.sqlalchemy.org/en/14/core/metadata.html#column-table-metadata-api
|
4
5
|
# CursorResult
|
@@ -17,10 +18,10 @@ from sqlalchemy.orm import DeclarativeBase
|
|
17
18
|
from . import utils
|
18
19
|
|
19
20
|
|
20
|
-
class Database
|
21
|
+
class Database:
|
21
22
|
"""Database"""
|
22
23
|
|
23
|
-
engine = create_engine(
|
24
|
+
engine = create_engine("sqlite://")
|
24
25
|
|
25
26
|
def __init__(self, target: str | None = None, **options):
|
26
27
|
"""Initiation"""
|
@@ -85,10 +86,10 @@ class Database():
|
|
85
86
|
except Exception as e:
|
86
87
|
logger.exception(e)
|
87
88
|
idx.create(bind=self.engine)
|
88
|
-
logger.success(f
|
89
|
+
logger.success(f"{info} [success]")
|
89
90
|
return True
|
90
91
|
except Exception as e:
|
91
|
-
logger.error(f
|
92
|
+
logger.error(f"{info} [failed]")
|
92
93
|
logger.error(e)
|
93
94
|
return False
|
94
95
|
|
@@ -227,10 +228,10 @@ class Database():
|
|
227
228
|
self,
|
228
229
|
sql: str | None = None,
|
229
230
|
read_sql_file: dict | None = None,
|
230
|
-
save_to_csv: dict | None = None
|
231
|
+
save_to_csv: dict | None = None,
|
231
232
|
) -> CursorResult[Any] | bool | None:
|
232
233
|
|
233
|
-
info: str =
|
234
|
+
info: str = "Database connect execute"
|
234
235
|
|
235
236
|
logger.info(f"{info} ......")
|
236
237
|
|
@@ -245,12 +246,12 @@ class Database():
|
|
245
246
|
read_sql_file_kwargs: dict = {
|
246
247
|
"mode": "r",
|
247
248
|
"encoding": "utf-8",
|
248
|
-
**read_sql_file
|
249
|
+
**read_sql_file,
|
249
250
|
}
|
250
251
|
with open(encoding="utf-8", **read_sql_file_kwargs) as _file:
|
251
252
|
sql_statement = _file.read()
|
252
253
|
else:
|
253
|
-
if not
|
254
|
+
if not isinstance(sql, str):
|
254
255
|
return None
|
255
256
|
sql_statement = sql
|
256
257
|
except Exception as e:
|
@@ -278,7 +279,7 @@ class Database():
|
|
278
279
|
save_to_csv_kwargs: dict = {
|
279
280
|
"mode": "w",
|
280
281
|
"encoding": "utf-8",
|
281
|
-
**save_to_csv
|
282
|
+
**save_to_csv,
|
282
283
|
}
|
283
284
|
with open(encoding="utf-8", **save_to_csv_kwargs) as _file:
|
284
285
|
return self._result_save(_file, result)
|
@@ -293,12 +294,7 @@ class Database():
|
|
293
294
|
|
294
295
|
# ----------------------------------------------------------------------------------------------
|
295
296
|
|
296
|
-
def read_with_pandas(
|
297
|
-
self,
|
298
|
-
method: str = "read_sql",
|
299
|
-
result_type: str = "df",
|
300
|
-
**kwargs
|
301
|
-
) -> pd.DataFrame | list | dict:
|
297
|
+
def read_with_pandas(self, method: str = "read_sql", result_type: str = "df", **kwargs) -> pd.DataFrame | list | dict:
|
302
298
|
"""读取数据"""
|
303
299
|
|
304
300
|
# 使用SQL查询数据: 使用 pd.read_sql 的参数
|
@@ -309,12 +305,6 @@ class Database():
|
|
309
305
|
|
310
306
|
data: pd.DataFrame = pd.DataFrame()
|
311
307
|
|
312
|
-
if not utils.check_arguments([(method, str, "method")]):
|
313
|
-
return data
|
314
|
-
|
315
|
-
if not utils.check_arguments([(result_type, str, "result_type")]):
|
316
|
-
return data
|
317
|
-
|
318
308
|
info: str = "read data"
|
319
309
|
|
320
310
|
try:
|
@@ -322,7 +312,7 @@ class Database():
|
|
322
312
|
logger.info(f"{info} ......")
|
323
313
|
|
324
314
|
# 从 kwargs 中删除 con 键
|
325
|
-
kwargs.pop(
|
315
|
+
kwargs.pop("con", None)
|
326
316
|
|
327
317
|
match method:
|
328
318
|
case "read_sql":
|
@@ -343,12 +333,12 @@ class Database():
|
|
343
333
|
|
344
334
|
match result_type:
|
345
335
|
case "json":
|
346
|
-
return json.loads(data.to_json(orient=
|
336
|
+
return json.loads(data.to_json(orient="records"))
|
347
337
|
case "dict":
|
348
338
|
return data.to_dict()
|
349
339
|
case "list":
|
350
340
|
# https://stackoverflow.com/a/26716774
|
351
|
-
return data.to_dict(
|
341
|
+
return data.to_dict("list")
|
352
342
|
case _:
|
353
343
|
return data
|
354
344
|
|
ezKit/dockerhub.py
CHANGED
@@ -1,9 +1,12 @@
|
|
1
|
-
"""Docker Hub"""
|
1
|
+
"""Docker Hub Library"""
|
2
|
+
|
2
3
|
import requests
|
3
4
|
from loguru import logger
|
4
5
|
|
5
6
|
|
6
|
-
def get_latest_tags(
|
7
|
+
def get_latest_tags(
|
8
|
+
url: str, limit: int = 20, proxies: dict | None = None
|
9
|
+
) -> list | None:
|
7
10
|
|
8
11
|
info: str = "获取最新标签"
|
9
12
|
|
@@ -20,7 +23,9 @@ def get_latest_tags(url: str, limit: int = 20, proxies: dict | None = None) -> l
|
|
20
23
|
# }
|
21
24
|
|
22
25
|
# 请求接口
|
23
|
-
response = requests.get(
|
26
|
+
response = requests.get(
|
27
|
+
url, params={"page": 1, "page_size": limit}, proxies=proxies, timeout=10
|
28
|
+
)
|
24
29
|
|
25
30
|
# 检查请求状态码
|
26
31
|
if response.status_code != 200:
|
@@ -47,6 +52,7 @@ def get_latest_tags(url: str, limit: int = 20, proxies: dict | None = None) -> l
|
|
47
52
|
logger.exception(e)
|
48
53
|
return None
|
49
54
|
|
55
|
+
|
50
56
|
# def get_all_tags():
|
51
57
|
# url = "https://hub.docker.com/v2/repositories/library/postgres/tags"
|
52
58
|
# tags = []
|
ezKit/http.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""HTTP"""
|
1
|
+
"""HTTP Library"""
|
2
|
+
|
2
3
|
import json
|
3
4
|
from typing import Any
|
4
5
|
|
@@ -13,7 +14,7 @@ def download(
|
|
13
14
|
file: dict,
|
14
15
|
chunks: bool = False,
|
15
16
|
iter_content: dict | None = None,
|
16
|
-
info: str | None = None
|
17
|
+
info: str | None = None,
|
17
18
|
) -> bool:
|
18
19
|
"""下载文件"""
|
19
20
|
|
@@ -38,7 +39,7 @@ def download(
|
|
38
39
|
|
39
40
|
try:
|
40
41
|
|
41
|
-
logger.info(f
|
42
|
+
logger.info(f"{info_prefix} ......")
|
42
43
|
|
43
44
|
response = requests.request(**request_arguments)
|
44
45
|
|
@@ -51,13 +52,13 @@ def download(
|
|
51
52
|
else:
|
52
53
|
_file.write(response.content)
|
53
54
|
|
54
|
-
logger.success(f
|
55
|
+
logger.success(f"{info_prefix} [success]")
|
55
56
|
|
56
57
|
return True
|
57
58
|
|
58
59
|
except Exception as e:
|
59
60
|
|
60
|
-
logger.error(f
|
61
|
+
logger.error(f"{info_prefix} [failed]")
|
61
62
|
logger.exception(e)
|
62
63
|
return False
|
63
64
|
|
@@ -65,7 +66,9 @@ def download(
|
|
65
66
|
def response_json(data: Any = None, **kwargs) -> str | None:
|
66
67
|
"""解决字符编码问题: ensure_ascii=False"""
|
67
68
|
try:
|
68
|
-
return json.dumps(
|
69
|
+
return json.dumps(
|
70
|
+
data, default=str, ensure_ascii=False, sort_keys=True, **kwargs
|
71
|
+
)
|
69
72
|
except Exception as e:
|
70
73
|
logger.exception(e)
|
71
74
|
return None
|
ezKit/mongo.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""MongoDB"""
|
1
|
+
"""MongoDB Library"""
|
2
|
+
|
2
3
|
from loguru import logger
|
3
4
|
from pymongo import MongoClient
|
4
5
|
from pymongo.collection import Collection
|
@@ -6,7 +7,7 @@ from pymongo.collection import Collection
|
|
6
7
|
from . import utils
|
7
8
|
|
8
9
|
|
9
|
-
class Mongo
|
10
|
+
class Mongo:
|
10
11
|
"""MongoDB"""
|
11
12
|
|
12
13
|
client = MongoClient()
|
ezKit/qywx.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""
|
1
|
+
"""腾讯企业微信"""
|
2
|
+
|
2
3
|
#
|
3
4
|
# 企业微信开发者中心
|
4
5
|
# https://developer.work.weixin.qq.com/
|
@@ -60,7 +61,13 @@ class QYWX:
|
|
60
61
|
# Token: https://developer.work.weixin.qq.com/document/path/90665#access-token
|
61
62
|
access_token: str = ""
|
62
63
|
|
63
|
-
def __init__(
|
64
|
+
def __init__(
|
65
|
+
self,
|
66
|
+
work_id: str,
|
67
|
+
agent_id: str,
|
68
|
+
agent_secret: str,
|
69
|
+
api_prefix: str = "https://qyapi.weixin.qq.com",
|
70
|
+
):
|
64
71
|
"""Initiation"""
|
65
72
|
self.api_prefix = api_prefix
|
66
73
|
self.work_id = work_id
|
@@ -79,7 +86,10 @@ class QYWX:
|
|
79
86
|
|
80
87
|
logger.info(f"{info} ......")
|
81
88
|
|
82
|
-
response = requests.get(
|
89
|
+
response = requests.get(
|
90
|
+
f"{self.api_prefix}/cgi-bin/gettoken?corpid={self.work_id}&corpsecret={self.agent_secret}",
|
91
|
+
timeout=10,
|
92
|
+
)
|
83
93
|
|
84
94
|
if response.status_code != 200:
|
85
95
|
logger.error(f"{info} [状态码错误]")
|
@@ -159,10 +169,6 @@ class QYWX:
|
|
159
169
|
|
160
170
|
info: str = f"根据电话号码获取用户ID: {mobile}"
|
161
171
|
|
162
|
-
if not utils.check_arguments([(mobile, str, "mobile")]):
|
163
|
-
logger.error(f"{info} [错误]")
|
164
|
-
return None
|
165
|
-
|
166
172
|
try:
|
167
173
|
|
168
174
|
logger.info(f"{info} ......")
|
@@ -170,9 +176,13 @@ class QYWX:
|
|
170
176
|
if not utils.isTrue(self.access_token, str):
|
171
177
|
self.get_access_token()
|
172
178
|
|
173
|
-
json_string = json.dumps({
|
179
|
+
json_string = json.dumps({"mobile": mobile})
|
174
180
|
|
175
|
-
response = requests.post(
|
181
|
+
response = requests.post(
|
182
|
+
f"{self.api_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}",
|
183
|
+
data=json_string,
|
184
|
+
timeout=10,
|
185
|
+
)
|
176
186
|
|
177
187
|
if response.status_code != 200:
|
178
188
|
logger.error(f"{info} [接口请求错误]")
|
@@ -180,7 +190,7 @@ class QYWX:
|
|
180
190
|
|
181
191
|
response_data: dict = response.json()
|
182
192
|
|
183
|
-
if response_data.get(
|
193
|
+
if response_data.get("errcode") == 42001:
|
184
194
|
self.get_access_token()
|
185
195
|
time.sleep(1)
|
186
196
|
self.get_user_id_by_mobile(mobile)
|
@@ -222,10 +232,6 @@ class QYWX:
|
|
222
232
|
|
223
233
|
info: str = "发送消息"
|
224
234
|
|
225
|
-
if not utils.check_arguments([(mobile, (str, list), "mobile"), (message, str, "message")]):
|
226
|
-
logger.error(f"{info} [失败]")
|
227
|
-
return False
|
228
|
-
|
229
235
|
try:
|
230
236
|
|
231
237
|
logger.info(f"{info} ......")
|
@@ -260,19 +266,23 @@ class QYWX:
|
|
260
266
|
continue
|
261
267
|
|
262
268
|
json_dict = {
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
269
|
+
"touser": user_object.get("userid"),
|
270
|
+
"msgtype": "text",
|
271
|
+
"agentid": self.agent_id,
|
272
|
+
"text": {"content": message},
|
273
|
+
"safe": 0,
|
274
|
+
"enable_id_trans": 0,
|
275
|
+
"enable_duplicate_check": 0,
|
276
|
+
"duplicate_check_interval": 1800,
|
271
277
|
}
|
272
278
|
|
273
279
|
json_string = json.dumps(json_dict)
|
274
280
|
|
275
|
-
response = requests.post(
|
281
|
+
response = requests.post(
|
282
|
+
f"{self.api_prefix}/cgi-bin/message/send?access_token={self.access_token}",
|
283
|
+
data=json_string,
|
284
|
+
timeout=10,
|
285
|
+
)
|
276
286
|
|
277
287
|
if response.status_code != 200:
|
278
288
|
logger.error(f"{info} [发送消息失败: {user}]")
|
@@ -280,7 +290,7 @@ class QYWX:
|
|
280
290
|
|
281
291
|
response_data: dict = response.json()
|
282
292
|
|
283
|
-
if response_data.get(
|
293
|
+
if response_data.get("errcode") == 42001:
|
284
294
|
self.get_access_token()
|
285
295
|
time.sleep(1)
|
286
296
|
self.send_message_by_mobile(mobile, message)
|
ezKit/redis.py
CHANGED
ezKit/sendemail.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""
|
1
|
+
"""Send eMail Library"""
|
2
|
+
|
2
3
|
# https://stackoverflow.com/questions/882712/sending-html-email-using-python
|
3
4
|
import smtplib
|
4
5
|
from email.header import Header
|
@@ -15,33 +16,40 @@ from . import utils
|
|
15
16
|
|
16
17
|
class TypedSMTP(TypedDict):
|
17
18
|
"""smtp type"""
|
19
|
+
|
18
20
|
server: str
|
19
21
|
port: int
|
20
22
|
tls: bool
|
21
23
|
|
24
|
+
|
22
25
|
class TypedSender(TypedDict):
|
23
26
|
"""sender type"""
|
27
|
+
|
24
28
|
name: str
|
25
29
|
address: str
|
26
30
|
password: str
|
27
31
|
|
32
|
+
|
28
33
|
class TypedBody(TypedDict, total=False):
|
29
34
|
"""body type"""
|
35
|
+
|
30
36
|
content: str
|
31
37
|
type: str | None # "plain", "html", or "file"
|
32
38
|
|
39
|
+
|
33
40
|
def format_parse(s):
|
34
41
|
"""格式化邮件地址"""
|
35
42
|
_name, _addr = parseaddr(s)
|
36
43
|
return formataddr((Header(_name, "utf-8").encode(), _addr))
|
37
44
|
|
45
|
+
|
38
46
|
def sendemail(
|
39
47
|
smtp: TypedSMTP,
|
40
48
|
sender: TypedSender,
|
41
49
|
recipients: str | list,
|
42
50
|
subject: str,
|
43
51
|
body: TypedBody,
|
44
|
-
images: None | list = None
|
52
|
+
images: None | list = None,
|
45
53
|
) -> bool:
|
46
54
|
"""发送邮件"""
|
47
55
|
|
@@ -233,10 +241,10 @@ def sendemail(
|
|
233
241
|
except Exception as e:
|
234
242
|
|
235
243
|
# 忽略腾讯邮箱返回的异常
|
236
|
-
if e.args == (-1, b
|
244
|
+
if e.args == (-1, b"\x00\x00\x00"):
|
237
245
|
# pass
|
238
246
|
return True
|
239
247
|
|
240
|
-
logger.error(
|
248
|
+
logger.error("sendemail error")
|
241
249
|
logger.exception(e)
|
242
250
|
return False
|
ezKit/token.py
CHANGED
@@ -1,4 +1,5 @@
|
|
1
|
-
"""Token"""
|
1
|
+
"""Token Library"""
|
2
|
+
|
2
3
|
import json
|
3
4
|
from typing import Any
|
4
5
|
|
@@ -7,7 +8,9 @@ from loguru import logger
|
|
7
8
|
from . import cipher, utils
|
8
9
|
|
9
10
|
|
10
|
-
def generate_token(
|
11
|
+
def generate_token(
|
12
|
+
key: str = "Fc0zXCmGKd7tPu6W", timeout: int = 3600, data: Any = None
|
13
|
+
) -> str | None:
|
11
14
|
try:
|
12
15
|
now = utils.datetime_now()
|
13
16
|
|
@@ -20,14 +23,11 @@ def generate_token(key: str = 'Fc0zXCmGKd7tPu6W', timeout: int = 3600, data: Any
|
|
20
23
|
return None
|
21
24
|
|
22
25
|
source = json.dumps(
|
23
|
-
obj={
|
24
|
-
|
25
|
-
"data": data
|
26
|
-
},
|
27
|
-
default=str
|
26
|
+
obj={"datetime": utils.datetime_to_string(offset), "data": data},
|
27
|
+
default=str,
|
28
28
|
)
|
29
29
|
|
30
|
-
aes_cipher = cipher.AESCipher(key=key, algorithm=
|
30
|
+
aes_cipher = cipher.AESCipher(key=key, algorithm="sha256")
|
31
31
|
|
32
32
|
return aes_cipher.encrypt(source)
|
33
33
|
|
@@ -36,12 +36,12 @@ def generate_token(key: str = 'Fc0zXCmGKd7tPu6W', timeout: int = 3600, data: Any
|
|
36
36
|
return None
|
37
37
|
|
38
38
|
|
39
|
-
def parsing_token(token_string: str, key: str =
|
39
|
+
def parsing_token(token_string: str, key: str = "Fc0zXCmGKd7tPu6W") -> dict | None:
|
40
40
|
try:
|
41
41
|
if not utils.isTrue(token_string, str):
|
42
42
|
return None
|
43
43
|
|
44
|
-
aes_cipher = cipher.AESCipher(key=key, algorithm=
|
44
|
+
aes_cipher = cipher.AESCipher(key=key, algorithm="sha256")
|
45
45
|
|
46
46
|
target = aes_cipher.decrypt(token_string)
|
47
47
|
|
@@ -50,7 +50,7 @@ def parsing_token(token_string: str, key: str = 'Fc0zXCmGKd7tPu6W') -> (dict | N
|
|
50
50
|
|
51
51
|
source: dict = json.loads(target)
|
52
52
|
|
53
|
-
source[
|
53
|
+
source["datetime"] = utils.datetime_string_to_datetime(source["datetime"])
|
54
54
|
|
55
55
|
return source
|
56
56
|
|
@@ -59,7 +59,7 @@ def parsing_token(token_string: str, key: str = 'Fc0zXCmGKd7tPu6W') -> (dict | N
|
|
59
59
|
return None
|
60
60
|
|
61
61
|
|
62
|
-
def certify_token(token_string: str, key: str =
|
62
|
+
def certify_token(token_string: str, key: str = "Fc0zXCmGKd7tPu6W") -> bool:
|
63
63
|
try:
|
64
64
|
|
65
65
|
result = parsing_token(token_string, key)
|
@@ -67,7 +67,7 @@ def certify_token(token_string: str, key: str = 'Fc0zXCmGKd7tPu6W') -> bool:
|
|
67
67
|
if result is None:
|
68
68
|
return False
|
69
69
|
|
70
|
-
if result.get(
|
70
|
+
if result.get("datetime") < utils.datetime_now(): # type: ignore
|
71
71
|
return False
|
72
72
|
|
73
73
|
return True
|