威胁模型:拥有普通账号的已登录用户攻击服务器。完整审计报告见
_experiments/security_audit_2026-09-02/(不入库),含实测复现记录。
严重/高危修复:
- 彻底移除文件夹打包下载(/api/download/folder 端点删除,gui/api_v1
目录下载分支改 410):文件型符号链接会被宿主进程解析,实测可读宿主
任意文件(含 settings.json 全部 LLM 密钥),删除比补校验更彻底
- XFF 伪造防护:get_client_ip 仅信任 ASTRION_TRUSTED_PROXIES
(默认空=不信 XFF);登录新增账号维度锁定(5 次失败锁 300s);
注册邀请码加爆破锁定;限流桶/失败表加 2 万键上限+GC 回收
- auth_debug.log 接入大小轮转;/api/client_debug_log 加限流+长度截断
- /host-login 增加 LINUX_SAFETY 检查且仅回环地址可用
容器加固:
- 默认 cpus=1 / memory=1g,新增 pids-limit=512、memory-swap、
no-new-privileges
- 新增每用户容器配额 MAX_ACTIVE_CONTAINERS_PER_USER(默认 3),
防止单用户占满全局容器池
api_v1:
- prompts/personalizations 的 name 加白名单校验(^[A-Za-z0-9_-]{1,64}$),
修复路径穿越写入;对话元数据中的引用名同步加白名单
- workspaces/conversations/messages/upload 四端点加用户维度限流
- 消息体加 MAX_MESSAGE_CHARS 上限(默认 200000,/api/tasks 同步)
- _path_within 加分隔符边界(修复 startswith 前缀碰撞)
其他:
- SVG 预览强制 application/octet-stream(修存储型 XSS 漏网)
- monitor_snapshot 缓存键加 username 维度(修跨用户快照读取)
- ensure/delete_workspace 加 workspace_id 白名单+父目录二次核验
- delete_folder 拒绝删除工作区根(crud_mixin 与容器代理同步修)
- GuiFileManager 死代码加名称校验防复活
- admin_dashboard 静态壳非 admin 访问一律 404
- /api/app/apk/latest 加登录校验+限流(原未认证可拉 133MB)
有意未修(见报告 7.3 遗留清单):容器 egress 过滤(部署层)、
--cap-drop ALL(怕破坏容器内工作流,已先上 no-new-privileges)、
API 用户/子智能体 LLM 按 token 计费(待产品决策)、str(exc) 收口、
WebSocket 限流、network_permission=restricted 容器语义。
验证:全部文件 py_compile 通过;冒烟测试 6/6 通过;关键新逻辑
(名称校验/路径边界/容器代理删除防护/限流回收)已单测级验证;
端点级行为待服务重启后实测复核(清单见报告 7.5)。
Co-authored-by: Astrion powered by Kimi-K3 <astrion-agent@users.noreply.github.com>
273 lines
12 KiB
Python
273 lines
12 KiB
Python
"""Backend i18n message pack: file_manager-family user-visible messages.
|
||
|
||
Covers modules/file_manager/ (base.py, path_mixin.py, read_mixin.py,
|
||
list_mixin.py, crud_mixin.py, patch_mixin.py, replace_mixin.py). Pure data
|
||
module — do not import anything here. Auto-discovered and merged by
|
||
modules/i18n.py at import time.
|
||
zh-CN copy is verbatim from source; en-US is concise product-level
|
||
English (sentence case).
|
||
"""
|
||
|
||
MESSAGES = {
|
||
# ── base.py(容器未就绪) ──
|
||
"file_manager.container_not_ready": {
|
||
"zh-CN": "容器未就绪,无法执行文件操作",
|
||
"en-US": "Container is not ready; cannot perform file operations",
|
||
},
|
||
|
||
# ── path_mixin.py(_validate_path / _ensure_host_access,传播到多处显示) ──
|
||
"file_manager.path_outside_workspace_detailed": {
|
||
"zh-CN": "路径必须在项目文件夹内。请检查是否使用的是不带/workspace的相对路径。",
|
||
"en-US": "Path must be inside the project folder. Please use a relative path without /workspace.",
|
||
},
|
||
"file_manager.path_outside_project": {
|
||
"zh-CN": "路径必须在项目文件夹内",
|
||
"en-US": "Path must be inside the project folder",
|
||
},
|
||
"file_manager.path_traversal_blocked": {
|
||
"zh-CN": "不允许使用../向上遍历",
|
||
"en-US": "Path traversal (../) is not allowed",
|
||
},
|
||
"file_manager.path_forbidden_root": {
|
||
"zh-CN": "禁止访问根目录: {path}",
|
||
"en-US": "Access to root directory is forbidden: {path}",
|
||
},
|
||
"file_manager.path_forbidden_system": {
|
||
"zh-CN": "禁止访问系统目录: {path}",
|
||
"en-US": "Access to system directory is forbidden: {path}",
|
||
},
|
||
"file_manager.host_access_write_denied": {
|
||
"zh-CN": "目标路径不在可写授权范围内,请在路径授权中添加后重试。",
|
||
"en-US": "Target path is outside the writable authorization scope. Please add it to path authorization and retry.",
|
||
},
|
||
"file_manager.host_access_read_denied": {
|
||
"zh-CN": "目标路径不在可读授权范围内,请在路径授权中添加后重试。",
|
||
"en-US": "Target path is outside the readable authorization scope. Please add it to path authorization and retry.",
|
||
},
|
||
|
||
# ── read_mixin.py ──
|
||
"file_manager.file_not_found": {
|
||
"zh-CN": "文件不存在",
|
||
"en-US": "File not found",
|
||
},
|
||
"file_manager.file_too_large": {
|
||
"zh-CN": "文件太大 ({size}MB > {limit}MB)",
|
||
"en-US": "File too large ({size}MB > {limit}MB)",
|
||
},
|
||
"file_manager.not_utf8_text": {
|
||
"zh-CN": "文件不是 UTF-8 文本,无法直接读取,请改用 run_command 调用合适的解析工具或 Python 解释器。",
|
||
"en-US": "File is not UTF-8 text and cannot be read directly. Use run_command with a suitable parser or Python instead.",
|
||
},
|
||
"file_manager.read_failed": {
|
||
"zh-CN": "读取文件失败: {error}",
|
||
"en-US": "Failed to read file: {error}",
|
||
},
|
||
"file_manager.not_a_file": {
|
||
"zh-CN": "不是文件",
|
||
"en-US": "Not a file",
|
||
},
|
||
"file_manager.start_line_out_of_file": {
|
||
"zh-CN": "起始行超出文件长度",
|
||
"en-US": "Start line exceeds the file length",
|
||
},
|
||
"file_manager.missing_search_query": {
|
||
"zh-CN": "缺少搜索关键词",
|
||
"en-US": "Search query is missing",
|
||
},
|
||
"file_manager.missing_segments": {
|
||
"zh-CN": "缺少要提取的行区间",
|
||
"en-US": "Missing segments to extract",
|
||
},
|
||
"file_manager.segments_items_must_be_objects": {
|
||
"zh-CN": "segments 数组中的每一项都必须是对象",
|
||
"en-US": "Every item in the segments array must be an object",
|
||
},
|
||
"file_manager.segments_need_line_bounds": {
|
||
"zh-CN": "所有区间都必须包含 start_line 和 end_line",
|
||
"en-US": "Every segment must include start_line and end_line",
|
||
},
|
||
"file_manager.segment_range_invalid": {
|
||
"zh-CN": "行区间不合法",
|
||
"en-US": "Invalid line range",
|
||
},
|
||
"file_manager.segment_start_exceeds": {
|
||
"zh-CN": "区间起点 {line} 超出文件行数",
|
||
"en-US": "Segment start line {line} exceeds the file line count",
|
||
},
|
||
|
||
# ── list_mixin.py ──
|
||
"file_manager.line_start_must_be_one": {
|
||
"zh-CN": "行号必须从1开始",
|
||
"en-US": "Line numbers must start at 1",
|
||
},
|
||
"file_manager.end_line_lt_start_line": {
|
||
"zh-CN": "结束行号不能小于起始行号",
|
||
"en-US": "End line cannot be smaller than the start line",
|
||
},
|
||
"file_manager.edit_start_line_out_of_range": {
|
||
"zh-CN": "起始行号 {start_line} 超出文件范围 (共 {total_lines} 行)",
|
||
"en-US": "Start line {start_line} is out of the file range (file has {total_lines} lines)",
|
||
},
|
||
"file_manager.edit_end_line_out_of_range": {
|
||
"zh-CN": "结束行号 {end_line} 超出文件范围 (共 {total_lines} 行)",
|
||
"en-US": "End line {end_line} is out of the file range (file has {total_lines} lines)",
|
||
},
|
||
"file_manager.unknown_operation": {
|
||
"zh-CN": "未知的操作类型: {operation}",
|
||
"en-US": "Unknown operation type: {operation}",
|
||
},
|
||
"file_manager.dir_not_found": {
|
||
"zh-CN": "目录不存在",
|
||
"en-US": "Directory not found",
|
||
},
|
||
"file_manager.not_a_directory": {
|
||
"zh-CN": "不是目录",
|
||
"en-US": "Not a directory",
|
||
},
|
||
"file_manager.desc_replace_lines": {
|
||
"zh-CN": "替换第 {start}-{end} 行",
|
||
"en-US": "Replaced lines {start}-{end}",
|
||
},
|
||
"file_manager.desc_insert_before": {
|
||
"zh-CN": "在第 {line} 行前插入",
|
||
"en-US": "Inserted before line {line}",
|
||
},
|
||
"file_manager.desc_delete_lines": {
|
||
"zh-CN": "删除第 {start}-{end} 行",
|
||
"en-US": "Deleted lines {start}-{end}",
|
||
},
|
||
|
||
# ── crud_mixin.py ──
|
||
"file_manager.original_not_found": {
|
||
"zh-CN": "原文件不存在",
|
||
"en-US": "Original file not found",
|
||
},
|
||
"file_manager.target_exists": {
|
||
"zh-CN": "目标文件已存在",
|
||
"en-US": "Target file already exists",
|
||
},
|
||
"file_manager.folder_exists": {
|
||
"zh-CN": "文件夹已存在",
|
||
"en-US": "Folder already exists",
|
||
},
|
||
"file_manager.folder_not_found": {
|
||
"zh-CN": "文件夹不存在",
|
||
"en-US": "Folder not found",
|
||
},
|
||
"file_manager.cannot_delete_workspace_root": {
|
||
"zh-CN": "不允许删除工作区根目录",
|
||
"en-US": "Deleting the workspace root is not allowed",
|
||
},
|
||
"file_manager.not_a_folder": {
|
||
"zh-CN": "不是文件夹",
|
||
"en-US": "Not a folder",
|
||
},
|
||
"file_manager.content_too_long": {
|
||
"zh-CN": "内容过长({length}字符),超过100KB限制",
|
||
"en-US": "Content too long ({length} chars); exceeds the 100KB limit",
|
||
},
|
||
"file_manager.storage_quota_exceeded": {
|
||
"zh-CN": "写入失败:超出项目磁盘配额",
|
||
"en-US": "Write failed: project disk quota exceeded",
|
||
},
|
||
|
||
# ── patch_mixin.py (apply_diff_patch / apply_modify_blocks) ──
|
||
"file_manager.patch_missing_markers": {
|
||
"zh-CN": "补丁格式错误:缺少 *** Begin Patch / *** End Patch 标记。",
|
||
"en-US": "Patch format error: missing *** Begin Patch / *** End Patch markers.",
|
||
},
|
||
"file_manager.patch_bad_end_marker": {
|
||
"zh-CN": "补丁格式错误:结束标记位置异常。",
|
||
"en-US": "Patch format error: end marker position is invalid.",
|
||
},
|
||
"file_manager.patch_block_empty": {
|
||
"zh-CN": "补丁块缺少内容:{header}",
|
||
"en-US": "Patch block is missing content: {header}",
|
||
},
|
||
"file_manager.patch_block_id_not_int": {
|
||
"zh-CN": "补丁块编号必须是整数:{header}",
|
||
"en-US": "Patch block id must be an integer: {header}",
|
||
},
|
||
"file_manager.patch_content_before_first_block": {
|
||
"zh-CN": "补丁格式错误:在检测到第一个 @@ 块之前出现内容。",
|
||
"en-US": "Patch format error: content appears before the first @@ block.",
|
||
},
|
||
"file_manager.patch_no_blocks": {
|
||
"zh-CN": "补丁格式错误:未检测到任何 @@ [id:n] 块。",
|
||
"en-US": "Patch format error: no @@ [id:n] blocks found.",
|
||
},
|
||
"file_manager.patch_block_no_content": {
|
||
"zh-CN": "补丁块 {index} 未包含任何 + / - / 上下文行。",
|
||
"en-US": "Patch block {index} contains no + / - / context lines.",
|
||
},
|
||
"file_manager.patch_no_valid_blocks": {
|
||
"zh-CN": "未检测到有效的补丁块。",
|
||
"en-US": "No valid patch blocks detected.",
|
||
},
|
||
"file_manager.append_write_failed": {
|
||
"zh-CN": "追加写入失败: {error}",
|
||
"en-US": "Failed to append: {error}",
|
||
},
|
||
"file_manager.write_failed": {
|
||
"zh-CN": "写入文件失败: {error}",
|
||
"en-US": "Failed to write file: {error}",
|
||
},
|
||
"file_manager.patch_summary_header": {
|
||
"zh-CN": "向 {path} 应用 {total} 个补丁块",
|
||
"en-US": "Applied {total} patch blocks to {path}",
|
||
},
|
||
"file_manager.patch_summary_success": {
|
||
"zh-CN": "成功 {count} 个",
|
||
"en-US": "{count} succeeded",
|
||
},
|
||
"file_manager.patch_summary_failed": {
|
||
"zh-CN": "失败 {count} 个",
|
||
"en-US": "{count} failed",
|
||
},
|
||
"file_manager.patch_summary_append": {
|
||
"zh-CN": "追加 {blocks} 块,写入 {lines} 行({bytes} 字节)",
|
||
"en-US": "Appended {blocks} blocks, wrote {lines} lines ({bytes} bytes)",
|
||
},
|
||
|
||
# ── replace_mixin.py ──
|
||
"file_manager.replace_old_text_too_long": {
|
||
"zh-CN": "要替换的文本过长,可能导致性能问题",
|
||
"en-US": "Text to replace is too long and may cause performance issues",
|
||
},
|
||
"file_manager.replace_new_text_too_long": {
|
||
"zh-CN": "替换的新文本过长,建议分块处理",
|
||
"en-US": "Replacement text is too long; consider splitting it into smaller parts",
|
||
},
|
||
"file_manager.replace_not_found": {
|
||
"zh-CN": "未找到要替换的内容",
|
||
"en-US": "Replacement target not found",
|
||
},
|
||
"file_manager.replacements_required": {
|
||
"zh-CN": "replacements 必须是非空数组",
|
||
"en-US": "replacements must be a non-empty array",
|
||
},
|
||
"file_manager.replacements_too_many": {
|
||
"zh-CN": "replacements 数量过多,最多支持 100 组",
|
||
"en-US": "Too many replacements; at most 100 groups are supported",
|
||
},
|
||
"file_manager.replace_group_failed": {
|
||
"zh-CN": "第 {index} 组替换失败:{reason}",
|
||
"en-US": "Replacement group {index} failed: {reason}",
|
||
},
|
||
"file_manager.replace_found_report": {
|
||
"zh-CN": "发现{found}处,于{lines}行共替换{count}处",
|
||
"en-US": "Found {found} matches; replaced {count} at lines {lines}",
|
||
},
|
||
"file_manager.replace_short_old_notice": {
|
||
"zh-CN": "提示:old_string 少于3行,已继续执行;需要批量替换的场景可以单行或不足一行",
|
||
"en-US": "Note: old_string is shorter than 3 lines; execution continued. For batch replacement, use single-line or shorter strings",
|
||
},
|
||
"file_manager.replace_many_summary": {
|
||
"zh-CN": "共 {groups} 组替换,替换 {replacements} 处",
|
||
"en-US": "{groups} groups processed; {replacements} replacements made",
|
||
},
|
||
"file_manager.replace_many_short_notice": {
|
||
"zh-CN": "提示:第 {indices} 组 old_string 少于3行,已继续执行",
|
||
"en-US": "Note: old_string in groups {indices} is shorter than 3 lines; execution continued",
|
||
},
|
||
} |