fix(pages): normalize '.' path segments so ./-prefixed tar entries upload
GNU tar prefixes every entry with ./ when archiving a directory (tar czf out.tgz . yields ./index.html, ./bin_bg.wasm, …). The path validator rejected any '.' segment as traversal, so such tarballs failed with "archive entry has an unsafe path: './...'" and their ./index.html never satisfied the root-index.html requirement — making ./-prefixed archives unusable. (.wasm was never the issue: extensions aren't checked and mime.rs maps .wasm to application/wasm.) check_entry_path now strips '.' segments (leading and interior) and returns the normalized path used as the R2 key, while still rejecting '..', absolute paths, backslashes, NUL, drive letters, empty (//) segments, and names that normalize to nothing; depth is measured on the normalized path. Both the zip and tar manifest builders store the normalized name. +10 tests. Bean: pages-aalu. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>main
parent
0aa6a6862e
commit
f42ae56bb4
@ -0,0 +1,33 @@
|
||||
---
|
||||
# pages-aalu
|
||||
title: Normalize '.' path segments so ./-prefixed tar entries are accepted
|
||||
status: completed
|
||||
type: bug
|
||||
priority: high
|
||||
created_at: 2026-07-21T16:25:26Z
|
||||
updated_at: 2026-07-21T16:30:49Z
|
||||
---
|
||||
|
||||
## Symptom
|
||||
Uploading a GNU-tar-style tarball fails with `archive entry has an unsafe path: './bin_bg.wasm'` (a `PathTraversal` 400). Not wasm-specific — `.wasm` is fully allowed (mime.rs maps it to application/wasm; extensions are not checked on upload).
|
||||
|
||||
## Root cause
|
||||
`check_entry_path` (core/upload.rs ~664-670) splits the entry name on `/` and rejects any segment equal to `.` (alongside `..` and empty). GNU `tar czf out.tgz .` prefixes every entry with `./` (e.g. `./index.html`, `./bin_bg.wasm`), so the leading `.` segment trips the traversal guard. This also breaks the root-`index.html` requirement for such tarballs (`./index.html` != `index.html`), making `./`-prefixed archives unusable. Zip tools don't emit `./`, so only the new compressed-tar path exposed this.
|
||||
|
||||
## Fix
|
||||
Treat `.` segments as the no-ops they are: normalize them out (strip leading `./`, drop interior `.` segments) and use the normalized `/`-joined path as the stored R2 key. Keep rejecting `..`, absolute paths, backslashes, NUL, drive letters, over-length/over-depth, and empty-after-normalization. Apply to both zip and tar paths for consistency (share via `check_entry_path`). Depth is measured on the normalized path.
|
||||
|
||||
## Tasks
|
||||
- [x] Normalize `.` segments in check_entry_path; return the normalized path for use as the R2 key
|
||||
- [x] Update zip + tar manifest builders to store the normalized path (so index.html detection sees the normalized name)
|
||||
- [x] Tests: `./`-prefixed tar entry accepted (incl. ./index.html satisfies root requirement and ./bin_bg.wasm accepted), interior `./` normalized, `..` still rejected, `.`-only / empty-after-normalization rejected
|
||||
- [x] All six validation commands pass (native + wasm)
|
||||
- [x] Commit, push, deploy
|
||||
|
||||
## Summary of Changes
|
||||
|
||||
`check_entry_path` now returns the normalized path (`Result<String, _>`): `.` current-directory segments are stripped (leading `./` and interior `/./`) instead of rejected, while `..`, absolute paths, backslashes, NUL, drive letters, empty (`//`) segments, and names that normalize to nothing are still rejected. Depth is measured on the normalized segment count. Both `build_zip_manifest` and `read_tar_entries` store the normalized path, so a GNU-tar `./index.html` satisfies the root-level requirement and `./bin_bg.wasm` is accepted.
|
||||
|
||||
`.wasm` was never blocked — the upload validator does not check extensions, and `mime.rs` maps `.wasm` to `application/wasm`.
|
||||
|
||||
+10 tests: 3 tar `./`-prefix wrappers (gzip/zstd/xz) plus 7 direct `check_entry_path` cases (leading/interior `.` normalization, `..` still rejected, `.`-only rejected, empty segment rejected, depth measured post-normalization). All six validation commands pass: 196 unit + 20 doctests.
|
||||
Loading…
Reference in New Issue