lesscode-flask 0.2.102__tar.gz → 0.2.105__tar.gz
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.
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/PKG-INFO +1 -1
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/__init__.py +1 -1
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/cache.py +2 -1
- lesscode_flask-0.2.105/lesscode_flask/utils/sign/body_canonical.py +25 -0
- lesscode_flask-0.2.105/lesscode_flask/utils/sign/sign_main.py +95 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/sign/signature.py +7 -2
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/PKG-INFO +1 -1
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/SOURCES.txt +2 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/dameng.py +5 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/README.md +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/app.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/db/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/db/datasource.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/db/executor.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/export_data/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/export_data/data_download_handler.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/log/access_log_handler.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/access_log.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/base_model.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/parameterized_query.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/resource_param_template.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/response_result.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/user.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/user_limit_policy.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/service/access_log_service.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/service/base_service.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/service/resource_param_template_service.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/setting/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/setup/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/signals.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/static/swagger.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/sql_injection.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/swagger.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/dify_utils.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/file/file_exporter.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/file/file_utils.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/fs_util.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/helpers.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/consecutive/consecutive_limiter_handler.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/consecutive/redis_consecutive_limiter.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/limit_util.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/req/rate_limiter_handler.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/req/redis_rate_limiter.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/limit/req_count/redis_count_limiter.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/oss/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/oss/aliyun_oss.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/oss/minio_oss.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/redis/redis_helper.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/request/request.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/sign/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/task/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/task/task_helper.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/thread/thread_utils.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/wsgi.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/dependency_links.txt +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/requires.txt +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/top_level.txt +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/clickhouse.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/elasticsearch.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/kingbase.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/mysql.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/query_runner/pg.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/settings/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/settings/helpers.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/utils/__init__.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/redash/utils/requests_session.py +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/setup.cfg +0 -0
- {lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/setup.py +0 -0
|
@@ -133,7 +133,8 @@ def format_insert_key(signature, func_name, args, params):
|
|
|
133
133
|
if k != "self":
|
|
134
134
|
_args.append(f"{k}={json.dumps(params[k])}")
|
|
135
135
|
str_insert_key = "&".join([str(x) for x in _args])
|
|
136
|
-
headers = {key: value for key, value in request.headers if
|
|
136
|
+
headers = {key: value for key, value in request.headers if
|
|
137
|
+
key in ["App-Key", "Data-Source-Id", "Industry-Owner-Sign"]}
|
|
137
138
|
for h in headers:
|
|
138
139
|
str_insert_key = str_insert_key + "&" + str(headers[h])
|
|
139
140
|
str_insert_key = app_config.get("ROUTE_PREFIX") + "#" + func_name + "#" + str_insert_key
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import json
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def _is_json_content_type(content_type: str) -> bool:
|
|
5
|
+
normalized = (content_type or "").split(";", 1)[0].strip().lower()
|
|
6
|
+
return normalized == "application/json" or normalized.endswith("+json")
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def canonicalize_body_bytes(body_bytes: bytes, content_type: str = "") -> bytes:
|
|
10
|
+
"""
|
|
11
|
+
JSON 请求体统一规范化后再参与签名,避免不同链路重排字段顺序导致 hash 不一致。
|
|
12
|
+
非 JSON 请求体保持原始 bytes,不影响文件上传、表单和纯文本请求。
|
|
13
|
+
"""
|
|
14
|
+
if not body_bytes or not _is_json_content_type(content_type):
|
|
15
|
+
return body_bytes or b""
|
|
16
|
+
try:
|
|
17
|
+
payload = json.loads(body_bytes)
|
|
18
|
+
except (TypeError, ValueError):
|
|
19
|
+
return body_bytes
|
|
20
|
+
return json.dumps(
|
|
21
|
+
payload,
|
|
22
|
+
ensure_ascii=False,
|
|
23
|
+
separators=(",", ":"),
|
|
24
|
+
sort_keys=True,
|
|
25
|
+
).encode("utf-8")
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import hashlib
|
|
2
|
+
import hmac
|
|
3
|
+
import time
|
|
4
|
+
import uuid
|
|
5
|
+
from urllib.parse import urlparse
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def body_sha256(body_bytes: bytes) -> str:
|
|
9
|
+
"""对请求体原始 bytes 做 SHA256,保持与服务端 request.get_data() 一致。"""
|
|
10
|
+
return hashlib.sha256(body_bytes).hexdigest()
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def build_sign_content(method: str, path: str, query_string: str, body_bytes: bytes, timestamp: str, nonce: str) -> str:
|
|
14
|
+
"""
|
|
15
|
+
生成规范签名串:
|
|
16
|
+
METHOD \n PATH \n QUERY_STRING \n BODY_SHA256 \n TIMESTAMP \n NONCE
|
|
17
|
+
"""
|
|
18
|
+
return (
|
|
19
|
+
f"{method.upper()}\n"
|
|
20
|
+
f"{path}\n"
|
|
21
|
+
f"{query_string}\n"
|
|
22
|
+
f"{body_sha256(body_bytes)}\n"
|
|
23
|
+
f"{timestamp}\n"
|
|
24
|
+
f"{nonce}"
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def generate_signature(secret: str, sign_content: str) -> str:
|
|
29
|
+
"""用 HMAC-SHA256 生成十六进制签名。"""
|
|
30
|
+
return hmac.new(secret.encode("utf-8"), sign_content.encode("utf-8"), hashlib.sha256).hexdigest()
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
def parse_path_and_query(url: str) -> tuple[str, str]:
|
|
34
|
+
"""从完整 URL 提取 path 和 query_string。"""
|
|
35
|
+
parsed = urlparse(url)
|
|
36
|
+
path = parsed.path or "/"
|
|
37
|
+
query_string = parsed.query or ""
|
|
38
|
+
return path, query_string
|
|
39
|
+
|
|
40
|
+
|
|
41
|
+
def main():
|
|
42
|
+
# ===== 在这里粘贴你的请求信息(开始)=====
|
|
43
|
+
request_url = "http://localhost:8968/ike2b/navigation/cluster/test_sign"
|
|
44
|
+
request_method = "POST"
|
|
45
|
+
request_body = '{"type":1}'
|
|
46
|
+
sign_secret = "test_sign_secret"
|
|
47
|
+
# 可选:不填则自动生成
|
|
48
|
+
request_timestamp = ""
|
|
49
|
+
request_nonce = ""
|
|
50
|
+
# 可选:你的发送工具若会在 body 末尾补换行,改成 True
|
|
51
|
+
append_newline_to_body = False
|
|
52
|
+
# ===== 在这里粘贴你的请求信息(结束)=====
|
|
53
|
+
|
|
54
|
+
method = request_method.upper()
|
|
55
|
+
path, query_string = parse_path_and_query(request_url)
|
|
56
|
+
timestamp = request_timestamp or str(int(time.time()))
|
|
57
|
+
nonce = request_nonce or uuid.uuid4().hex
|
|
58
|
+
|
|
59
|
+
body = request_body or ""
|
|
60
|
+
body_bytes = body.encode("utf-8")
|
|
61
|
+
if append_newline_to_body:
|
|
62
|
+
body_bytes += b"\n"
|
|
63
|
+
|
|
64
|
+
sign_content = build_sign_content(
|
|
65
|
+
method=method,
|
|
66
|
+
path=path,
|
|
67
|
+
query_string=query_string,
|
|
68
|
+
body_bytes=body_bytes,
|
|
69
|
+
timestamp=timestamp,
|
|
70
|
+
nonce=nonce,
|
|
71
|
+
)
|
|
72
|
+
signature = generate_signature(sign_secret, sign_content)
|
|
73
|
+
body_hash = body_sha256(body_bytes)
|
|
74
|
+
|
|
75
|
+
print("=== 签名结果 ===")
|
|
76
|
+
print(f"Timestamp: {timestamp}")
|
|
77
|
+
print(f"Nonce: {nonce}")
|
|
78
|
+
print(f"Signature: {signature}")
|
|
79
|
+
print(f"Body-SHA256: {body_hash}")
|
|
80
|
+
print(f"Body-Bytes-Len: {len(body_bytes)}")
|
|
81
|
+
print()
|
|
82
|
+
print("=== 可直接追加到 curl 的请求头 ===")
|
|
83
|
+
print(f"--header 'Timestamp: {timestamp}' \\")
|
|
84
|
+
print(f"--header 'Nonce: {nonce}' \\")
|
|
85
|
+
print(f"--header 'Signature: {signature}'")
|
|
86
|
+
print()
|
|
87
|
+
print("=== 调试信息(参与签名的 body bytes)===")
|
|
88
|
+
print(repr(body_bytes))
|
|
89
|
+
print()
|
|
90
|
+
print("=== 调试信息(服务端签名原文)===")
|
|
91
|
+
print(sign_content)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
if __name__ == "__main__":
|
|
95
|
+
main()
|
|
@@ -8,6 +8,7 @@ from flask import request
|
|
|
8
8
|
|
|
9
9
|
from lesscode_flask.model.response_result import ResponseResult
|
|
10
10
|
from lesscode_flask.utils.redis.redis_helper import RedisHelper
|
|
11
|
+
from lesscode_flask.utils.sign.body_canonical import canonicalize_body_bytes
|
|
11
12
|
|
|
12
13
|
SIGN_ERROR_MESSAGE = "未知错误"
|
|
13
14
|
SIGN_ERROR_CODE_MAP = {
|
|
@@ -37,12 +38,16 @@ def _fail_sign(error_key: str):
|
|
|
37
38
|
|
|
38
39
|
|
|
39
40
|
def _body_sha256() -> str:
|
|
40
|
-
#
|
|
41
|
+
# JSON 请求先做规范化再哈希,避免中间链路重排字段顺序后签名失配。
|
|
41
42
|
body_bytes = request.get_data(cache=True) or b""
|
|
43
|
+
canonical_body_bytes = canonicalize_body_bytes(body_bytes, request.content_type or "")
|
|
42
44
|
logging.info("body_bytes开始")
|
|
43
45
|
logging.info("body_bytes: %s", body_bytes)
|
|
44
46
|
logging.info("body_bytes结束")
|
|
45
|
-
|
|
47
|
+
logging.info("canonical_body_bytes开始")
|
|
48
|
+
logging.info("canonical_body_bytes: %s", canonical_body_bytes)
|
|
49
|
+
logging.info("canonical_body_bytes结束")
|
|
50
|
+
return hashlib.sha256(canonical_body_bytes).hexdigest()
|
|
46
51
|
|
|
47
52
|
|
|
48
53
|
def _is_upload_request() -> bool:
|
|
@@ -54,6 +54,8 @@ lesscode_flask/utils/oss/minio_oss.py
|
|
|
54
54
|
lesscode_flask/utils/redis/redis_helper.py
|
|
55
55
|
lesscode_flask/utils/request/request.py
|
|
56
56
|
lesscode_flask/utils/sign/__init__.py
|
|
57
|
+
lesscode_flask/utils/sign/body_canonical.py
|
|
58
|
+
lesscode_flask/utils/sign/sign_main.py
|
|
57
59
|
lesscode_flask/utils/sign/signature.py
|
|
58
60
|
lesscode_flask/utils/swagger/swagger_template.py
|
|
59
61
|
lesscode_flask/utils/swagger/swagger_util.py
|
|
@@ -12,6 +12,11 @@ except ImportError:
|
|
|
12
12
|
logging.error("dmPython is not installed, run: pip install dmPython")
|
|
13
13
|
dmPython = None
|
|
14
14
|
enabled = False
|
|
15
|
+
try:
|
|
16
|
+
import nspydm as dmPython
|
|
17
|
+
enabled = True
|
|
18
|
+
except ImportError as e:
|
|
19
|
+
logging.error("ns-pydm is not installed, run: pip install ns-pydm")
|
|
15
20
|
|
|
16
21
|
logger = logging.getLogger(__name__)
|
|
17
22
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/parameterized_query.py
RENAMED
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/model/resource_param_template.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/service/access_log_service.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/__init__.py
RENAMED
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/decorator/sql_injection.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/file/file_exporter.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/json/NotSortJSONProvider.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/redis/redis_helper.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/swagger/swagger_template.py
RENAMED
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/swagger/swagger_util.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask/utils/thread/thread_utils.py
RENAMED
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.102 → lesscode_flask-0.2.105}/lesscode_flask.egg-info/dependency_links.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|