fix(project_file): path/project_id循环unquote兼容前端双重编码——bricks.tget对已编码query值再encodeURIComponent一次(双重编码),服务端只解一层残留%XX编码态中文→项目名_ident_ok校验失败误报'非法路径'(2026-09-16投标标书md在线查看实测根因;下载走window.open单层编码不受影响,故只有在线查看中招)。对齐workspace_view.dspy的_decode_id循环解码到无%。共享端点:task_io/todo_detail/workspace全部md在线查看一并根治
This commit is contained in:
parent
28a26dc01f
commit
f05d95b8ac
@ -4,15 +4,32 @@
|
||||
# 安全:仅登录用户;解析后校验文件真实路径必须落在该项目目录内(防路径穿越/跨项目越权)。
|
||||
|
||||
import os
|
||||
from urllib.parse import quote
|
||||
from urllib.parse import quote, unquote
|
||||
from aiohttp.web_fileresponse import FileResponse
|
||||
|
||||
|
||||
def _decode_path(s):
|
||||
# 前端 bricks.tget 会对已编码的 query 值再 encodeURIComponent 一次(双重编码),
|
||||
# 服务端框架只解一层 → 残留 %XX 编码态中文 → 项目名/文件名校验失败,
|
||||
# 误报「非法路径」或「文件不存在」(2026-09-16 投标标书 md 在线查看实测根因;
|
||||
# 下载按钮走 window.open 单层编码不受影响,故只有「在线查看」中招)。
|
||||
# 循环 unquote 到无 % 为止,兼容任意编码层数(对齐 workspace_view.dspy 的 _decode_id)。
|
||||
for _ in range(4):
|
||||
if '%' not in s:
|
||||
break
|
||||
s2 = unquote(s)
|
||||
if s2 == s:
|
||||
break
|
||||
s = s2
|
||||
return s
|
||||
|
||||
|
||||
uid = await get_user()
|
||||
if not uid:
|
||||
return {"widgettype": "Message", "options": {"title": "未登录", "message": "请先登录"}}
|
||||
|
||||
project_id = ((params_kw or {}).get('project_id') or '').strip()
|
||||
fpath = ((params_kw or {}).get('path') or '').strip()
|
||||
project_id = _decode_path(((params_kw or {}).get('project_id') or '').strip())
|
||||
fpath = _decode_path(((params_kw or {}).get('path') or '').strip())
|
||||
download = ((params_kw or {}).get('download') or '').strip()
|
||||
|
||||
if not project_id:
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user