lesscode-flask 0.2.9__tar.gz → 0.2.11__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.9 → lesscode_flask-0.2.11}/PKG-INFO +1 -1
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/__init__.py +1 -1
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/app.py +5 -2
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/setting/__init__.py +6 -1
- lesscode_flask-0.2.11/lesscode_flask/utils/decorator/sql_injection.py +73 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/limit_util.py +2 -1
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/req/redis_rate_limiter.py +3 -2
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask.egg-info/PKG-INFO +1 -1
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask.egg-info/SOURCES.txt +1 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/README.md +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/db/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/db/datasource.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/db/executor.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/export_data/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/export_data/data_download_handler.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/log/access_log_handler.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/access_log.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/base_model.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/parameterized_query.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/resource_param_template.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/response_result.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/user.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/service/access_log_service.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/service/base_service.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/service/resource_param_template_service.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/setup/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/signals.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/static/swagger.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/decorator/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/decorator/cache.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/decorator/swagger.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/dify_utils.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/file/file_exporter.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/file/file_utils.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/fs_util.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/helpers.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/json/NotSortJSONProvider.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/req/rate_limiter_handler.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/req_count/count_limiter_handler.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/req_count/redis_count_limiter.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/oss/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/oss/aliyun_oss.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/oss/ks3_oss.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/oss/minio_oss.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/redis/redis_helper.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/request/request.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/swagger/swagger_template.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/swagger/swagger_util.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/task/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/task/task_helper.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/thread/thread_utils.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/wsgi.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask.egg-info/dependency_links.txt +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask.egg-info/requires.txt +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask.egg-info/top_level.txt +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/clickhouse.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/elasticsearch.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/kingbase.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/mysql.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/query_runner/pg.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/settings/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/settings/helpers.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/utils/__init__.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/redash/utils/requests_session.py +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/setup.cfg +0 -0
- {lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/setup.py +0 -0
|
@@ -20,6 +20,7 @@ from lesscode_flask.setup import setup_blueprint, setup_logging, setup_query_run
|
|
|
20
20
|
setup_redis, setup_login_manager, setup_resource_register, setup_data_download, setup_scheduler, \
|
|
21
21
|
setup_common_resource, setup_task
|
|
22
22
|
from lesscode_flask.signals import app_runed
|
|
23
|
+
from lesscode_flask.utils.decorator.sql_injection import contains_sql_injection
|
|
23
24
|
from lesscode_flask.utils.helpers import inject_args, generate_uuid, app_config
|
|
24
25
|
from lesscode_flask.utils.json.NotSortJSONProvider import NotSortJSONProvider
|
|
25
26
|
from lesscode_flask.utils.limit import RedisRateLimiter
|
|
@@ -68,7 +69,6 @@ class Lesscoder(Flask):
|
|
|
68
69
|
|
|
69
70
|
def preprocess_request(self) -> ft.ResponseReturnValue | None:
|
|
70
71
|
v = super(Lesscoder, self).preprocess_request()
|
|
71
|
-
|
|
72
72
|
if hasattr(self, 'countLimiter') and self.countLimiter:
|
|
73
73
|
allowed, remaining = self.countLimiter.is_allowed(*get_count_limit_info())
|
|
74
74
|
if not allowed:
|
|
@@ -143,7 +143,10 @@ class Lesscoder(Flask):
|
|
|
143
143
|
# 此处增加参数注入代码
|
|
144
144
|
params_dict = inject_args(req, func, view_args)
|
|
145
145
|
params_dict.update(view_args)
|
|
146
|
-
|
|
146
|
+
SQL_INJECTION_ENABLE = self.config.get("SQL_INJECTION_ENABLE", False)
|
|
147
|
+
if SQL_INJECTION_ENABLE:
|
|
148
|
+
if contains_sql_injection(params_dict):
|
|
149
|
+
ResponseResult.fail("参数包含非法字符,请调整后重试!", status_code="403", http_code="403")
|
|
147
150
|
# 调用处理函数执行请求处理
|
|
148
151
|
result = self.ensure_sync(func)(**params_dict)
|
|
149
152
|
# 获取不包装路径
|
|
@@ -94,7 +94,9 @@ class BaseConfig:
|
|
|
94
94
|
RATE_LIMIT_ENABLE: bool = False
|
|
95
95
|
# 触发限流的处理函数
|
|
96
96
|
RATE_LIMIT_HANDLER = RateLimitHandler
|
|
97
|
-
#
|
|
97
|
+
# 限流频率窗口 单位是每秒
|
|
98
|
+
RATE_LIMIT_TIME_WINDOW = 1
|
|
99
|
+
# 限流频率
|
|
98
100
|
RATE_LIMIT_RATE = 1
|
|
99
101
|
# 限流频率允许的突发值 请求速率超过(rate + brust)的请求会被直接拒绝。
|
|
100
102
|
RATE_LIMIT_BURST = 0
|
|
@@ -116,6 +118,9 @@ class BaseConfig:
|
|
|
116
118
|
"/ike2b/pool/company/area_distribution/park_company_count_by_special_tag"]
|
|
117
119
|
# 飞书 webhook URL 常量定义 用于向指定的飞书机器人发送消息的 webhook 地址
|
|
118
120
|
LIMIT_FS_WEBHOOK_URL = "https://open.feishu.cn/open-apis/bot/v2/hook/545140ef-8234-4167-9f0c-8ee72abae430"
|
|
121
|
+
|
|
122
|
+
# sql 注入验证器开关
|
|
123
|
+
SQL_INJECTION_ENABLE = False
|
|
119
124
|
#
|
|
120
125
|
#
|
|
121
126
|
# # 外网地址
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
import functools
|
|
2
|
+
import logging
|
|
3
|
+
import re
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def param_verification(func):
|
|
7
|
+
"""
|
|
8
|
+
装饰器函数,用于检测函数参数中是否包含 SQL 注入风险。
|
|
9
|
+
|
|
10
|
+
:param func: 被装饰的原始函数
|
|
11
|
+
:return: 包装后的函数,会在执行前进行 SQL 注入检测
|
|
12
|
+
"""
|
|
13
|
+
@functools.wraps(func)
|
|
14
|
+
def wrapper(*args, **kwargs):
|
|
15
|
+
# 检查关键字参数中是否包含 SQL 注入风险
|
|
16
|
+
if contains_sql_injection(kwargs):
|
|
17
|
+
raise Exception("SQL 注入 detected")
|
|
18
|
+
|
|
19
|
+
return func(*args, **kwargs)
|
|
20
|
+
|
|
21
|
+
return wrapper
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def is_sql_injection(value):
|
|
25
|
+
"""
|
|
26
|
+
检测字符串是否包含常见的 SQL 注入特征。
|
|
27
|
+
|
|
28
|
+
:param value: 待检测的字符串
|
|
29
|
+
:return: 如果包含 SQL 注入特征则返回 True,否则返回 False
|
|
30
|
+
"""
|
|
31
|
+
if not isinstance(value, str):
|
|
32
|
+
return False # 只检查字符串类型的数据
|
|
33
|
+
|
|
34
|
+
# 常见 SQL 注入特征
|
|
35
|
+
sql_patterns = [
|
|
36
|
+
r"(?i)(\bAND\b|\bOR\b)[\s(]*\d+[\s)]*=[\s(]*\d+[\s)]*", # 逻辑表达式
|
|
37
|
+
r"(?i)\b(select|union|insert|update|delete|drop|alter|create|truncate|exec|execute|sleep)\b", # 关键 SQL 语句
|
|
38
|
+
r"(?i)( or | and )\d+=\d+", # 布尔盲注
|
|
39
|
+
r"(?i)(char|concat|case when)\s*\(", # SQL 函数
|
|
40
|
+
r"(--|#|;)", # 注释符号或语句结束符
|
|
41
|
+
r"(?i)'[\s\d]*or[\s\d]*'", # 典型 SQL 盲注
|
|
42
|
+
]
|
|
43
|
+
|
|
44
|
+
for pattern in sql_patterns:
|
|
45
|
+
if re.search(pattern, value):
|
|
46
|
+
return True # 发现 SQL 注入特征
|
|
47
|
+
|
|
48
|
+
return False
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def contains_sql_injection(data):
|
|
52
|
+
"""
|
|
53
|
+
递归检测数据结构中是否包含 SQL 注入风险。
|
|
54
|
+
|
|
55
|
+
支持的数据类型包括:字符串、列表、元组和字典。
|
|
56
|
+
对于其他类型(如 int、float、None)将直接返回 False。
|
|
57
|
+
|
|
58
|
+
:param data: 待检测的数据,可以是任意嵌套结构
|
|
59
|
+
:return: 如果发现 SQL 注入风险则返回 True,否则返回 False
|
|
60
|
+
"""
|
|
61
|
+
if isinstance(data, str): # 单个字符串
|
|
62
|
+
return is_sql_injection(data)
|
|
63
|
+
|
|
64
|
+
if isinstance(data, list): # 列表中的每个元素
|
|
65
|
+
return any(contains_sql_injection(item) for item in data)
|
|
66
|
+
if isinstance(data, tuple): # 元组中的每个元素
|
|
67
|
+
return any(contains_sql_injection(item) for item in data)
|
|
68
|
+
|
|
69
|
+
if isinstance(data, dict): # 递归检查字典中的值
|
|
70
|
+
return any(contains_sql_injection(value) for value in data.values())
|
|
71
|
+
|
|
72
|
+
return False # 其他类型(int, float, None)不检测
|
|
73
|
+
|
|
@@ -33,8 +33,9 @@ def get_rate_limit_info() -> str:
|
|
|
33
33
|
"""
|
|
34
34
|
rate = app_config.get("RATE_LIMIT_RATE", 1) # 限流频率 单位是每秒
|
|
35
35
|
burst = app_config.get("RATE_LIMIT_BURST", 0) # 限流频率允许的突发值 请求速率超过(rate + brust)的请求会被直接拒绝。
|
|
36
|
+
time_window = app_config.get("RATE_LIMIT_TIME_WINDOW", 1) # 限流频率允许的突发值 请求速率超过(rate + brust)的请求会被直接拒绝。
|
|
36
37
|
limit_key = limit_key_encode()
|
|
37
|
-
return limit_key, rate, burst
|
|
38
|
+
return limit_key, rate, burst,time_window
|
|
38
39
|
|
|
39
40
|
def get_count_limit_info() -> str:
|
|
40
41
|
"""
|
{lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/limit/req/redis_rate_limiter.py
RENAMED
|
@@ -13,12 +13,13 @@ class RedisRateLimiter:
|
|
|
13
13
|
def __init__(self, redis_key):
|
|
14
14
|
self.redis_key = redis_key
|
|
15
15
|
|
|
16
|
-
def is_limited(self, key: str, rate: float, burst: float) -> tuple:
|
|
16
|
+
def is_limited(self, key: str, rate: float, burst: float,time_window:int=1) -> tuple:
|
|
17
17
|
"""
|
|
18
18
|
检查是否触发限流
|
|
19
19
|
:param key: 限流键
|
|
20
20
|
:param rate: 每秒请求速率
|
|
21
21
|
:param burst: 突发请求数
|
|
22
|
+
:param time_window: 窗口期
|
|
22
23
|
:return: (allowed,delay, excess) 是否触发限流 延迟时间和超出数量
|
|
23
24
|
"""
|
|
24
25
|
if not key: # 没有key表示不验证
|
|
@@ -44,7 +45,7 @@ class RedisRateLimiter:
|
|
|
44
45
|
# 计算当前与最近一次访问的时间差
|
|
45
46
|
elapsed = now - last
|
|
46
47
|
# 根据时间差计算当前的excess值
|
|
47
|
-
excess = max(excess - (rate * abs(elapsed) / 1000) + 1, 0)
|
|
48
|
+
excess = max(excess - (rate * abs(elapsed) / 1000*time_window) + 1, 0)
|
|
48
49
|
else:
|
|
49
50
|
excess = 0
|
|
50
51
|
# 返回延迟时间和超出数量
|
|
@@ -32,6 +32,7 @@ lesscode_flask/utils/fs_util.py
|
|
|
32
32
|
lesscode_flask/utils/helpers.py
|
|
33
33
|
lesscode_flask/utils/decorator/__init__.py
|
|
34
34
|
lesscode_flask/utils/decorator/cache.py
|
|
35
|
+
lesscode_flask/utils/decorator/sql_injection.py
|
|
35
36
|
lesscode_flask/utils/decorator/swagger.py
|
|
36
37
|
lesscode_flask/utils/file/file_exporter.py
|
|
37
38
|
lesscode_flask/utils/file/file_utils.py
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/export_data/data_download_handler.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/model/resource_param_template.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/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
|
{lesscode_flask-0.2.9 → lesscode_flask-0.2.11}/lesscode_flask/utils/swagger/swagger_template.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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|