feat: 文件管理器上传/下载 + 备份下载 - #1
Merged
Merged
Conversation
文件管理器:
- 上传:POST /files/upload,body 即文件原始字节,不引 multipart 依赖。
先写 .mcsp-upload-* 临时文件再 rename,中断不留半截文件;文件名必须单段,
超过 MCSP_MAX_UPLOAD_MB(默认 2048)立即断流回 413。
前端支持多选与拖拽,逐文件进度条,同名在开传前一次性确认。
- 下载:GET /files/download。文件走 res.download 原样回传(支持 Range);
目录现 tar czf - 流式打包,不落盘,客户端断开即 SIGKILL 掉 tar。
实例根目录不给下载,那是「备份」的活(会先 save-all)。
备份管理:
- 新增 GET /backups/:id/download,流式回传 tar.gz。
- listBackups 补 size 字节字段,前端改用 fmtSize —— 原来固定按 GB 显示,
小备份一律是 0.00 GB。
顺带修复路径穿越:/backups/:id 的 restore/delete 原本只检查 endsWith('.tar.gz'),
而 Express 会解码 :id,`..%2F..%2F` 能带着 path.join 走出 backups/ 目录。
三处改为共用 ^[\w.-]+\.tar\.gz$ 校验。
smoke 从 21 项加到 26 项(上传文件名/路径沙箱、下载路径沙箱、
下载实例根目录拒绝、备份 id 沙箱)。
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
做了什么
文件管理器 — 上传
POST /api/instances/:iid/files/upload?path=&name=&overwrite=,body 就是文件原始字节,没有引入新依赖(项目原本只有 express,multipart 解析要额外装包).mcsp-upload-<rand>临时文件再rename,上传中断不会在目录里留半截文件/\...与控制字符),目录复用原有safePath沙箱MCSP_MAX_UPLOAD_MB(默认 2048):Content-Length预检 + 流中途超限即断连回 413overwrite=1文件管理器 — 下载
GET /api/instances/:iid/files/download?path=res.download原样回传,不限扩展名,支持 Range 断点续传tar czf -流式打包,不落盘;客户端取消即 SIGKILL 掉 tar(否则一个大世界会白烧几分钟 CPU)save-all)备份管理 — 下载
GET /api/instances/:iid/backups/:id/download,流式回传 tar.gzlistBackups补size字节字段,前端改用fmtSize—— 原来固定按 GB 显示,小备份一律是0.00 GB顺带修复的路径穿越
/backups/:id的restore/delete原本只检查endsWith('.tar.gz')。Express 会解码:id,所以..%2F..%2F..%2Fetc%2Fpasswd.tar.gz能带着path.join走出backups/目录。三处改为共用^[\w.-]+\.tar\.gz$校验。验证
npm test26/26 通过(从 21 项加了 5 项:上传文件名/路径沙箱、下载路径沙箱、下载实例根目录拒绝、备份 id 沙箱)。脚本层另外验过:
Buffer.equals完全一致filename*=UTF-8''...世界目录/{level.dat, 说明.txt, region/r.0.0.mca}解开后内容与源文件逐字节一致;空目录也正常Content-Length预检 + chunked 中途掐断),临时文件无残留pgrep tar无残留浏览器实测:单文件、3 文件批量、覆盖确认(接受/取消)、超限失败 UI、目录与文件下载按钮均不会误触发行点击(打开编辑器/进入目录)。
已知限制
目录下载没有
Content-Length(边压边传决定的),浏览器进度条显示「未知大小」。要准确进度就得先压到磁盘再传,代价是大目录多占一份临时空间且首字节延迟高得多。🤖 Generated with Claude Code