Per-user home directories (v0.4 #16) #36

Merged
Cordy merged 3 commits from feat/per-user-homes into main 2026-07-25 20:31:29 +00:00
Owner

The authorization centerpiece: opt-in per-user home directories.

  • internal/storage/scope — a storage decorator (outermost) that rewrites each request's virtual namespace to /home/<username> for non-admins; admins (from auth.admins) see the whole backend. Home dirs are lazily created; the username is validated as a safe path segment; a user can't delete their own home root. Does not embed storage.Driver — every method is explicit so nothing bypasses scoping. Forwards Usage.
  • Opt-in via auth.perUserHomes (default off → unchanged flat behavior; the dogfood is unaffected until enabled).
  • Shares keep working: the public /s/ handler has no user context, so it's given the unscoped store, and share creation resolves the creator's path to its actual location (scope.Resolve) before persisting — so a shared /docs/x is stored as /home/alice/docs/x and served correctly.
  • Wired outermost in main.go (after encrypt/quota); admin set built once and reused.
  • Tests: home scoping on read/write/list (paths rewritten in and unscoped out), admin passthrough, Resolve, home-root delete guard, no-user rejection.

Consumes the group field from #17. Per-group /spaces/<group> (#16 cont.) builds on this next. Minor known cosmetic: GET /shares shows the stored actual path to the creator; display-unscoping is a small follow-up.

The authorization centerpiece: opt-in per-user home directories. - **`internal/storage/scope`** — a storage decorator (outermost) that rewrites each request's virtual namespace to `/home/<username>` for non-admins; admins (from `auth.admins`) see the whole backend. Home dirs are lazily created; the username is validated as a safe path segment; a user can't delete their own home root. Does **not** embed `storage.Driver` — every method is explicit so nothing bypasses scoping. Forwards `Usage`. - **Opt-in** via `auth.perUserHomes` (default off → unchanged flat behavior; the dogfood is unaffected until enabled). - **Shares keep working:** the public `/s/` handler has no user context, so it's given the **unscoped** store, and share creation resolves the creator's path to its actual location (`scope.Resolve`) before persisting — so a shared `/docs/x` is stored as `/home/alice/docs/x` and served correctly. - Wired outermost in `main.go` (after encrypt/quota); admin set built once and reused. - Tests: home scoping on read/write/list (paths rewritten in and unscoped out), admin passthrough, `Resolve`, home-root delete guard, no-user rejection. Consumes the group field from #17. Per-group `/spaces/<group>` (#16 cont.) builds on this next. Minor known cosmetic: `GET /shares` shows the stored actual path to the creator; display-unscoping is a small follow-up.
Cordy merged commit c92cd3929e into main 2026-07-25 20:31:29 +00:00
Sign in to join this conversation.
No reviewers
No labels
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference: Cordy/Cairn#36
No description provided.