voucher/scripts/load_path.py

103 lines
4.2 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

#!/usr/bin/env python3
"""voucher 模块 RBAC 路径权限注册pipeline-app 格式,仿 ticket/scripts/load_path.py
从应用根执行py3/bin/python pkgs/voucher/scripts/load_path.py
load_path.sh 自动扫描 pkgs/*/scripts/load_path.py 并调用本脚本)
权限设计(逐个精确配,不用统一兜底):
- logined客户侧「我的代金券」页面 + 自助查询 API + 管理侧全部页面与 API。
管理类数据面由服务端 org_id 隔离(模板带 org_id 列CRUD logined_userorgid 机制
不适用——平台运营代客户管券是本职,不做 org 过滤;误操作面由 helper 内校验兜底:
模板改删校验 org、实例改/作废只动 unused 券)。
- CRUD 生成目录voucher_*_list/四件套index.ui + get/add/update/delete dspy
逐一注册。
"""
import sys
import os
import asyncio
# 应用根:本脚本在 pkgs/voucher/scripts/ 下,上溯三级
APP_ROOT = os.path.abspath(os.path.join(os.path.dirname(os.path.abspath(__file__)), "../../.."))
sys.path.insert(0, os.path.join(APP_ROOT, "py3", "lib", "python3.10", "site-packages"))
sys.path.insert(0, APP_ROOT)
from sqlor.dbpools import DBPools
from appPublic.jsonConfig import getConfig
from appPublic.uniqueID import getID
MOD = "voucher"
# CRUD 生成目录四件套alias -> 表名)
CRUD_DIRS = {
"voucher_template_list": "voucher_template",
"voucher_rule_list": "voucher_rule",
"voucher_instance_list": "voucher_instance",
"voucher_usage_log_list": "voucher_usage_log",
}
PATHS_LOGINED = [
# 客户侧
f"/{MOD}/my",
f"/{MOD}/my/index.ui",
f"/{MOD}/api/my_vouchers.dspy",
f"/{MOD}/api/v1/available.dspy",
# 管理侧页面/表单
f"/{MOD}/index.ui",
f"/{MOD}/issue_form.ui",
f"/{MOD}/invalidate_form.ui",
# 管理侧 API
f"/{MOD}/api/get_available.dspy",
f"/{MOD}/api/apply_voucher.dspy",
f"/{MOD}/api/rule_types.dspy",
f"/{MOD}/api/template/voucher_template_create.dspy",
f"/{MOD}/api/template/voucher_template_update.dspy",
f"/{MOD}/api/template/voucher_template_delete.dspy",
f"/{MOD}/api/template/voucher_template_options.dspy",
f"/{MOD}/api/rule/voucher_rule_create.dspy",
f"/{MOD}/api/rule/voucher_rule_update.dspy",
f"/{MOD}/api/rule/voucher_rule_delete.dspy",
f"/{MOD}/api/instance/voucher_issue.dspy",
f"/{MOD}/api/instance/voucher_instance_update.dspy",
f"/{MOD}/api/instance/voucher_instance_delete.dspy",
f"/{MOD}/api/instance/voucher_invalidate.dspy",
]
# CRUD 生成目录(框架生成):只注册 index.ui + get_*.dspy只读
# ⚠ 生成的 add/update/delete_*.dspy 一律【不注册权限】——它们是裸 sor.C/U/D
# 绕过全部业务校验(发券引擎原子占额/流水审计只读/org 隔离/状态守卫)。
# 写操作只走 wwwroot/api/ 下有校验的端点UI 的 editable URL 已指向它们)。
# 文件虽被 xls2ui 生成noedit 也生成),无权限行即 401RBAC 默认拒绝)。
# 2026-09-12 实测抓到的漏洞:统一注册四件套后 update/delete_voucher_usage_log.dspy
# 登录态直接 200 可篡改审计流水——精确权限是防线,生成端点是攻击面。
for alias, tbl in CRUD_DIRS.items():
PATHS_LOGINED += [
f"/{MOD}/{alias}",
f"/{MOD}/{alias}/index.ui",
f"/{MOD}/{alias}/get_{tbl}.dspy",
]
async def main():
config = getConfig(APP_ROOT, NS={"workdir": APP_ROOT})
DBPools(config.databases)
cnt = 0
async with DBPools().sqlorContext("pipeline") as sor:
for path in PATHS_LOGINED:
recs = await sor.R("permission", {"path": path})
if recs:
permid = recs[0].id
else:
permid = getID()
await sor.C("permission", {"id": permid, "path": path})
rp = await sor.R("rolepermission", {"roleid": "logined", "permid": permid})
if not rp:
await sor.C("rolepermission", {
"id": getID(), "roleid": "logined", "permid": permid})
cnt += 1
await sor.sqlExe("COMMIT", {})
print(f"voucher load_path: {cnt} logined path-role entries ensured")
if __name__ == "__main__":
asyncio.run(main())