ezKit 1.12.0__py3-none-any.whl → 1.12.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.
- ezKit/bottle_extensions.py +8 -4
- ezKit/cipher.py +19 -16
- ezKit/database.py +20 -18
- ezKit/dockerhub.py +9 -3
- ezKit/http.py +9 -6
- ezKit/mongo.py +3 -2
- ezKit/qywx.py +47 -20
- ezKit/redis.py +2 -1
- ezKit/sendemail.py +12 -4
- ezKit/token.py +13 -13
- ezKit/utils.py +158 -230
- ezKit/xftp.py +39 -17
- ezKit/zabbix.py +140 -101
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/METADATA +1 -1
- ezkit-1.12.1.dist-info/RECORD +22 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/WHEEL +1 -1
- ezkit-1.12.0.dist-info/RECORD +0 -22
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.dist-info}/licenses/LICENSE +0 -0
- {ezkit-1.12.0.dist-info → ezkit-1.12.1.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,14 @@ 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 (
|
255
|
+
isinstance(sql, str) and utils.check_arguments([(sql, str, "sql")])
|
256
|
+
):
|
254
257
|
return None
|
255
258
|
sql_statement = sql
|
256
259
|
except Exception as e:
|
@@ -274,11 +277,13 @@ class Database():
|
|
274
277
|
logger.success(f"{info} [success]")
|
275
278
|
|
276
279
|
# 返回查询结果
|
277
|
-
if isinstance(save_to_csv, dict) and utils.isTrue(
|
280
|
+
if isinstance(save_to_csv, dict) and utils.isTrue(
|
281
|
+
save_to_csv, dict
|
282
|
+
):
|
278
283
|
save_to_csv_kwargs: dict = {
|
279
284
|
"mode": "w",
|
280
285
|
"encoding": "utf-8",
|
281
|
-
**save_to_csv
|
286
|
+
**save_to_csv,
|
282
287
|
}
|
283
288
|
with open(encoding="utf-8", **save_to_csv_kwargs) as _file:
|
284
289
|
return self._result_save(_file, result)
|
@@ -294,10 +299,7 @@ class Database():
|
|
294
299
|
# ----------------------------------------------------------------------------------------------
|
295
300
|
|
296
301
|
def read_with_pandas(
|
297
|
-
self,
|
298
|
-
method: str = "read_sql",
|
299
|
-
result_type: str = "df",
|
300
|
-
**kwargs
|
302
|
+
self, method: str = "read_sql", result_type: str = "df", **kwargs
|
301
303
|
) -> pd.DataFrame | list | dict:
|
302
304
|
"""读取数据"""
|
303
305
|
|
@@ -322,7 +324,7 @@ class Database():
|
|
322
324
|
logger.info(f"{info} ......")
|
323
325
|
|
324
326
|
# 从 kwargs 中删除 con 键
|
325
|
-
kwargs.pop(
|
327
|
+
kwargs.pop("con", None)
|
326
328
|
|
327
329
|
match method:
|
328
330
|
case "read_sql":
|
@@ -343,12 +345,12 @@ class Database():
|
|
343
345
|
|
344
346
|
match result_type:
|
345
347
|
case "json":
|
346
|
-
return json.loads(data.to_json(orient=
|
348
|
+
return json.loads(data.to_json(orient="records"))
|
347
349
|
case "dict":
|
348
350
|
return data.to_dict()
|
349
351
|
case "list":
|
350
352
|
# https://stackoverflow.com/a/26716774
|
351
|
-
return data.to_dict(
|
353
|
+
return data.to_dict("list")
|
352
354
|
case _:
|
353
355
|
return data
|
354
356
|
|
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} [状态码错误]")
|
@@ -170,9 +180,13 @@ class QYWX:
|
|
170
180
|
if not utils.isTrue(self.access_token, str):
|
171
181
|
self.get_access_token()
|
172
182
|
|
173
|
-
json_string = json.dumps({
|
183
|
+
json_string = json.dumps({"mobile": mobile})
|
174
184
|
|
175
|
-
response = requests.post(
|
185
|
+
response = requests.post(
|
186
|
+
f"{self.api_prefix}/cgi-bin/user/getuserid?access_token={self.access_token}",
|
187
|
+
data=json_string,
|
188
|
+
timeout=10,
|
189
|
+
)
|
176
190
|
|
177
191
|
if response.status_code != 200:
|
178
192
|
logger.error(f"{info} [接口请求错误]")
|
@@ -180,7 +194,7 @@ class QYWX:
|
|
180
194
|
|
181
195
|
response_data: dict = response.json()
|
182
196
|
|
183
|
-
if response_data.get(
|
197
|
+
if response_data.get("errcode") == 42001:
|
184
198
|
self.get_access_token()
|
185
199
|
time.sleep(1)
|
186
200
|
self.get_user_id_by_mobile(mobile)
|
@@ -222,7 +236,9 @@ class QYWX:
|
|
222
236
|
|
223
237
|
info: str = "发送消息"
|
224
238
|
|
225
|
-
if not utils.check_arguments(
|
239
|
+
if not utils.check_arguments(
|
240
|
+
[(mobile, (str, list), "mobile"), (message, str, "message")]
|
241
|
+
):
|
226
242
|
logger.error(f"{info} [失败]")
|
227
243
|
return False
|
228
244
|
|
@@ -251,28 +267,39 @@ class QYWX:
|
|
251
267
|
|
252
268
|
user_object = self.get_user_id_by_mobile(user)
|
253
269
|
|
254
|
-
if not (
|
270
|
+
if not (
|
271
|
+
isinstance(user_object, dict) and utils.isTrue(user_object, dict)
|
272
|
+
):
|
255
273
|
logger.error(f"{info} [获取用户ID错误: {user}]")
|
256
274
|
continue
|
257
275
|
|
258
|
-
if
|
259
|
-
|
276
|
+
if (
|
277
|
+
user_object.get("errcode", -1) != 0
|
278
|
+
or user_object.get("errmsg", "") != "ok"
|
279
|
+
):
|
280
|
+
logger.error(
|
281
|
+
f"{user_object.get('errcode')}: {user_object.get('errmsg')}"
|
282
|
+
)
|
260
283
|
continue
|
261
284
|
|
262
285
|
json_dict = {
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
286
|
+
"touser": user_object.get("userid"),
|
287
|
+
"msgtype": "text",
|
288
|
+
"agentid": self.agent_id,
|
289
|
+
"text": {"content": message},
|
290
|
+
"safe": 0,
|
291
|
+
"enable_id_trans": 0,
|
292
|
+
"enable_duplicate_check": 0,
|
293
|
+
"duplicate_check_interval": 1800,
|
271
294
|
}
|
272
295
|
|
273
296
|
json_string = json.dumps(json_dict)
|
274
297
|
|
275
|
-
response = requests.post(
|
298
|
+
response = requests.post(
|
299
|
+
f"{self.api_prefix}/cgi-bin/message/send?access_token={self.access_token}",
|
300
|
+
data=json_string,
|
301
|
+
timeout=10,
|
302
|
+
)
|
276
303
|
|
277
304
|
if response.status_code != 200:
|
278
305
|
logger.error(f"{info} [发送消息失败: {user}]")
|
@@ -280,7 +307,7 @@ class QYWX:
|
|
280
307
|
|
281
308
|
response_data: dict = response.json()
|
282
309
|
|
283
|
-
if response_data.get(
|
310
|
+
if response_data.get("errcode") == 42001:
|
284
311
|
self.get_access_token()
|
285
312
|
time.sleep(1)
|
286
313
|
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
|