Skip to content

fix(files): authorize downloads for wrapper apps via signed tokens - #528

Open
xiaojueshi wants to merge 1 commit into
agegr:mainfrom
xiaojueshi:fix/signed-download-token
Open

fix(files): authorize downloads for wrapper apps via signed tokens#528
xiaojueshi wants to merge 1 commit into
agegr:mainfrom
xiaojueshi:fix/signed-download-token

Conversation

@xiaojueshi

Copy link
Copy Markdown
Contributor

目的

Pi Web 可以开启 PI_WEB_PASSWORD(HTTP Basic 认证)。当页面被桌面封装应用
(如 Pake)包裹时,文件浏览器的下载会持续报
401 Unauthorized:封装应用会用自己的 HTTP 客户端重放下载链接,而该客户端
不携带 webview 已缓存的 Basic 凭据。

实现方式

用一段绑定文件路径、短时有效的签名令牌,替代缺失的 Basic 凭据,仅作用于
文件下载这一个请求:

  • app/api/auth/download-token(新增):在通过常规的 allowed-roots 校验
    (并对符号链接二次校验)后,为文件签发 5 分钟的 HMAC 签名令牌。端点本身
    仍受 Basic 认证保护。
  • proxy.ts:匹配 /api/files/**?type=download 且携带有效令牌的请求跳过
    Basic 检查;令牌无效或过期则显式返回 403。其余所有 /api/* 请求保持
    密码保护不变。
  • components/FileExplorer.tsx:悬停(hover)时预取令牌并写入下载链接的
    href——因为封装应用在 capture 阶段拦截点击,任何 React 点击处理器都来不及
    再取令牌。仅对封装应用会接管的扩展名附加可读文件名(download 属性)。
  • lib/download-auth.ts / lib/pake-download-extensions.ts(新增)及单元
    测试:覆盖签名/校验、过期、防篡改,以及镜像封装应用可下载扩展名清单的边界。

带来的变化

  • 开启 PI_WEB_PASSWORD 时,封装应用内下载恢复正常。
  • 非封装(浏览器)下载行为完全不变,含 Content-Disposition 文件名。
  • 安全性:令牌绑定文件路径、5 分钟过期,且仅对 type=download 形态生效,
    不能用于其他 API。签名密钥为进程内随机值(不落盘),除非显式设置
    PI_WEB_DOWNLOAD_SECRET

测试

  • 单元测试:lib/download-auth.test.mjs(7 项)、lib/pake-download-extensions.test.mjs(4 项)。
  • 集成验证(curl):携带令牌下载返回 200 且字节数完整;缺失/无效/过期/
    篡改路径的令牌被拒绝(401/403);Basic 认证下载回归通过。
  • 已在 Pake 封装环境实测:docx/xlsx 下载成功且文件名为可读中文。

Wrapper apps (e.g. Pake) replay file-download links through their own HTTP
client, which does not carry the page's Basic credentials, so every download
behind PI_WEB_PASSWORD fails with 401. Add a short-lived signed download token
(bound to the path, 5-min TTL) issued by a new endpoint and verified in the
proxy, so downloads pass without Basic auth while all other API requests stay
password-protected.

- app/api/auth/download-token/route.ts: issue tokens for files inside allowed
  roots (symlinks re-checked); Basic auth guarded by the proxy.
- proxy.ts: download requests with a valid token skip the Basic check; invalid
  tokens get an explicit 403.
- components/FileExplorer.tsx: prefetch the token on hover and write it into
  the download href before Pake's capture-phase click interception; attach a
  readable name via the download attribute only for extensions Pake hijacks.
- lib/download-auth.ts + lib/pake-download-extensions.ts with unit tests.

Verified with curl against a dev server: token download returns 200 with full
bytes, missing/invalid/expired tokens are rejected, basic-auth downloads
regress clean.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant