Commit graph

3168 commits

Author SHA1 Message Date
Henrique Dias
1cd18d7ead
docs: include issue summary in readme 2026-07-27 22:04:46 +02:00
Henrique Dias
e8a388f840
chore(release): 2.63.23 2026-07-27 21:50:03 +02:00
Henrique Dias
0dfe44649c
docs: cleanup header 2026-07-27 21:49:14 +02:00
Henrique Dias
05ee853eef
docs: clear inconsistencies, point at repo instead of website 2026-07-27 21:47:58 +02:00
Henrique Dias
afeb478ee1
chore(release): 2.63.22 2026-07-27 17:29:26 +02:00
Henrique Dias
df2869993a
chore: remove renovate.json 2026-07-27 17:29:12 +02:00
transifex-integration[bot]
d49ab67904
chore: update translations 2026-07-27 17:24:27 +02:00
superafun
cfff84306a
fix: use absolute URLs for the PWA manifest icon sources (#6032) 2026-07-27 17:23:54 +02:00
Henrique Dias
72faf6dd3c
fix: enforce rules on recursive operations and expired proxy tokens (#6053) 2026-07-27 17:16:58 +02:00
superafun
a789f29cee
fix: make the sidebar scrollable when content overflows (#6031) 2026-07-27 17:10:57 +02:00
Henrique Dias
74b13db3fa
docs: fix date 2026-07-27 17:02:02 +02:00
Henrique Dias
773b30102c
docs: add wind down notice 2026-07-27 16:58:50 +02:00
Henrique Dias
0b925cbca9
fix: unblock stalled and frozen uploads
A TUS PATCH rejected before its body was read left the client still streaming
a chunk. net/http gives up draining an unread request body after 256KiB and
then closes the connection, so the status we replied with was lost and the
browser saw a bare transport error instead. The client could not tell a
conflict from a network fault, retried blindly, and the upload stalled after
the first chunk — while curl, which reads the response as it writes, still
reported the status and appeared to work. Drain what is left of a rejected
chunk so the answer arrives on a connection that stays usable. The explicit
r.Body.Close() had to go with it: it ran before the drain, and the server
closes the request body itself once the handler returns.

Pressing Upload awaited a recursive listing of the whole destination subtree
before a single byte was sent, with no sign that anything was happening. On a
large destination that reads as a dead button, and the walk kept running after
the client gave up, then reported the failed write as a 500. A flat upload can
only collide with a direct child of the destination, so walk recursively only
for folder uploads, stop the walk once the request is done, and show the action
as busy while the destination is checked.

Along the way: a failed upload was credited as fully sent, so the progress bar
reported 100% when nothing had been written; the progress timer was recreated
without clearing the previous one; and the chunk size field threw on a value
with no unit and raced its own debounce on submit, so it appeared to refuse
every change.

Fixes #6006
Refs #5987
2026-07-27 16:28:17 +02:00
renovate[bot]
9dd7c7d099
chore(deps): update dependency postcss to v8.5.18 [security] (#6047) 2026-07-27 07:47:17 +02:00
Henrique Dias
b24e43b06c
chore: fix renovate.json order 2026-07-27 07:42:09 +02:00
renovate[bot]
91e68edb8c
chore(deps): update dependency dompurify to v3.4.12 [security] (#6046) 2026-07-27 07:41:48 +02:00
Henrique Dias
ac11538f08
chore: update renovate.json 2026-07-26 22:41:19 +02:00
Henrique Dias
f6fb8f6bf5
chore(release): 2.63.21 2026-07-26 10:02:11 +02:00
Henrique Dias
e6d70cf24c
fix(http): canonicalize paths before checking access rules (#6045) 2026-07-26 10:00:18 +02:00
Henrique Dias
41e2b1bbba
docs: update CLAUDE.md 2026-07-26 09:58:40 +02:00
Henrique Dias
41b01a7404
chore: update Go deps 2026-07-26 08:01:32 +02:00
Henrique Dias
0dd8905886
Revert "chore(deps): update all non-major dependencies (#5946)"
This reverts commit 032271bafa.
2026-07-26 08:00:07 +02:00
renovate[bot]
032271bafa
chore(deps): update all non-major dependencies (#5946) 2026-07-26 07:58:26 +02:00
Henrique Dias
50125a5d21
chore(release): 2.63.20 2026-07-25 22:16:14 +02:00
Henrique Dias
bc3d75a94a
test(users): cover concurrent provisioning into one scope
Two usernames that normalize to the same home directory must not both be
provisioned when their requests are handled concurrently. Also cover that
an explicit, non-derived scope may still be legitimately shared.

Refs GHSA-j7jh-37pf-mf8h
2026-07-25 22:15:35 +02:00
Henrique Dias
fb6aeba9ea
fix(users): make the provisioned scope check atomic with the save
The check that stops two usernames normalizing to the same home directory
ran as a storage operation separate from the save, so two first-time users
provisioned concurrently could both observe a free scope and both be saved
into it, ending up sharing one home directory.

Move the check into users.Storage.SaveProvisioned, which holds a single
lock across the lookup and the save, and reduce CreateUserHome to deriving
and creating the directory. This covers all three provisioning paths:
signup, proxy auth and hook auth.

Refs GHSA-j7jh-37pf-mf8h
2026-07-25 22:15:27 +02:00
Henrique Dias
67e893eee7
fix: use aria-selected 2026-07-25 22:09:01 +02:00
Henrique Dias
4a4b0f8c84
docs: update CLAUDE instructions 2026-07-25 22:03:33 +02:00
Henrique Dias
660d84661d
docs: update CLAUDE.md 2026-07-25 08:47:34 +02:00
Henrique Dias
392253c563
docs: update SECURITY.md and add CLAUDE.md 2026-07-25 08:42:52 +02:00
Henrique Dias
328f629181
chore(release): 2.63.19 2026-07-25 08:19:11 +02:00
Henrique Dias
4c3cb4bc9b
test(http): cover TUS Upload-Length enforcement
Refs GHSA-ffv3-7h97-993q
2026-07-25 08:16:19 +02:00
Henrique Dias
3213b605be
test(http): cover scope-safe removal on TUS upload eviction
Refs GHSA-m9f5-2232-frp6
2026-07-25 08:16:19 +02:00
Henrique Dias
610e0b09e9
test(http): cover download-permission gate on the checksum branch
Refs GHSA-7whw-q6gh-xr59
2026-07-25 08:16:19 +02:00
Henrique Dias
7453c78c98
test(storage): cover case-insensitive GetByScope matching
Refs GHSA-576v-w77m-gr84
2026-07-25 08:16:18 +02:00
Henrique Dias
cd5749dff8
test(auth): cover per-user scope isolation for proxy and hook provisioning
Unit tests for Settings.CreateUserHome (derives a per-user home, rejects a
colliding scope, preserves an explicit scope) plus proxy and hook regression
tests asserting that with CreateUserDir enabled two provisioned users receive
distinct home directories instead of the server root.

Refs GHSA-j7jh-37pf-mf8h, GHSA-j2fc-28fx-hc8q
2026-07-25 08:16:18 +02:00
Henrique Dias
4daddec6f2
fix(http): enforce declared Upload-Length on TUS uploads
The TUS PATCH handler copied the whole request body to disk and used the
declared Upload-Length only to decide when the upload was complete. A client
could declare a tiny Upload-Length and then stream an arbitrarily large body
in a single PATCH, writing it all to disk, so any user with create permission
could exhaust the filesystem.

Bound each write to the bytes still expected (Upload-Length - Upload-Offset),
reject a PATCH whose offset already exceeds the declared length, and roll back
and reject a body that exceeds it. This complements the existing negative
Upload-Length handling.

Refs GHSA-ffv3-7h97-993q
2026-07-25 08:16:18 +02:00
Henrique Dias
9bd79c3aae
fix(http): delete abandoned TUS uploads through the scoped filesystem
The in-memory upload cache deleted expired incomplete uploads with a raw
os.Remove on the absolute path it had stored, bypassing ScopedFs entirely.
Because the stored path is only lexically cleaned (no symlink evaluation) and
os.Remove resolves symlinked parent directories, a Create-only user could
register an upload and then, within the 3-minute TTL, swap an in-scope
ancestor directory for a symlink so the eviction deleted an arbitrary file
outside their scope.

Carry a removal callback with each cache entry and invoke it on eviction
instead of os.Remove. For TUS uploads the callback deletes via the uploading
user's scoped filesystem, whose Remove is guarded by the same within() check
that CVE-2026-55667 added, so eviction can no longer follow a symlink out of
scope. The redis backend ignores the callback (it never deleted partial files).

Refs GHSA-m9f5-2232-frp6
2026-07-25 08:16:18 +02:00
Henrique Dias
6c69b5cd89
fix(http): enforce download permission on the checksum branch
The ?checksum= branch of the resource GET handler read the whole file to
compute its digest and returned it without checking Perm.Download, unlike the
sibling raw, preview, subtitle and X-Encoding paths. A user provisioned with
Perm.Download=false could therefore obtain md5/sha1/sha256/sha512 digests of
files they are not allowed to download, giving a file-content hash oracle, and
force a full-file read.

Return 202 Accepted before computing the checksum when the user lacks
Perm.Download, matching the other read paths. This completes the fix for
CVE-2026-35606, whose original patch gated only the content-returning paths.

Refs GHSA-7whw-q6gh-xr59
2026-07-25 08:16:18 +02:00
Henrique Dias
4b8a8d72ce
fix(storage): reject case-folded home directory collisions
GetByScope compared scopes with a case-sensitive exact match, so on a
case-insensitive filesystem two accounts whose scopes differ only in case
(e.g. /users/CaseVictim and /users/casevictim) were treated as distinct even
though both resolve to the same physical home directory. The second account
could then read, overwrite and delete the first account's files.

Match the scope case-insensitively so the collision check performed during
signup, proxy and hook provisioning catches these aliases and rejects the
duplicate.

Refs GHSA-576v-w77m-gr84
2026-07-25 08:16:18 +02:00
Henrique Dias
8ddd3d1db9
fix(auth): isolate auto-provisioned proxy and hook users to their own home
Proxy- and hook-authenticated users were auto-provisioned by applying the
default scope (".") and passing it straight to MakeUserDir, which normalizes
"." to "/". With CreateUserDir enabled, every provisioned user therefore
received the server root as its scope instead of a per-user home directory,
letting one user read, overwrite and delete another user's files.

The signup handler already cleared the scope before deriving the home
directory. Centralize that logic into Settings.CreateUserHome (clear the
scope when CreateUserDir is on and no explicit scope was supplied, derive the
home dir, then reject a scope already owned by another user) and use it from
signup, proxy and hook auth so the three provisioning paths cannot diverge.

Refs GHSA-j7jh-37pf-mf8h, GHSA-j2fc-28fx-hc8q
2026-07-25 08:16:15 +02:00
Henrique Dias
9fffee387f
docs: remove go report 2026-07-25 08:00:00 +02:00
Henrique Dias
5a12cad548
docs: update readme 2026-07-25 07:52:21 +02:00
transifex-integration[bot]
6232686e22
chore: update translations 2026-07-25 07:30:18 +02:00
superafun
b21b1245ae
fix: accessibility and security improvements (#6033) 2026-07-25 07:30:02 +02:00
Archit Goyal
7361d91ea2
fix(upload): handle encoded path conflicts safely (#6040) 2026-07-25 07:29:49 +02:00
Henrique Dias
c05c668148
fix: process --FollowExternalSymlinks 2026-07-25 07:25:26 +02:00
Henrique Dias
b7dc392838
docs: fix typo 2026-07-21 19:18:51 +02:00
TowyTowy
ac46cf0671
fix: return error instead of panicking on an unreadable directory during copy (#6020)
Co-authored-by: Claude Fable 5 <noreply@anthropic.com>
2026-07-18 07:21:44 +02:00
transifex-integration[bot]
f0785391bf
chore: update translations (#6019)
Co-authored-by: transifex-integration[bot] <43880903+transifex-integration[bot]@users.noreply.github.com>
2026-07-18 07:20:43 +02:00