Address code review findings across API, web and deployment
release gate / check (push) Failing after 6m43s
release gate / check (push) Failing after 6m43s
High severity: - wire TRUSTED_PROXY through Compose/deploy/docs and warn at web startup - bucket public rate limits on effective client IP, add per-bookmark budget, and forward the signed browser identity from the share page - disable first-run bootstrap in server deployments and document seeding - serialize last-admin demotion in one advisory-locked transaction Medium/low: - cap and batch share recipient inserts - add a shared outbound budget for preview/CardDAV/IMAP/signal work - pin CardDAV dials to 443 and bound IMAP logout - fix rightward kanban column drags and normalize cards on column delete - classify backend outages in auth guards, add request timeouts and an error boundary, remove the dead login route, surface throttling - enforce pinned/unpinned page reorder grouping server-side - avoid preview work for stale bookmark versions; drop duplicate dialog fetch - sequence-guard collection/tag/calendar/quick-find loads - validate property config and fix MULTI_SELECT/DATE filter inputs - document index maintenance; apply same-origin check to sign-out - trim signup names, unique shared dates and kanban keys (migration 010), reset reference cache on identity changes, hide OIDC issuer, return 413 for oversized direct bodies, escape Markdown link destinations - remove dead template files and duplicate test helper Verified with go build/vet, full PostgreSQL race suite, db convergence, tsc, both ESLint configs and a Next production build.
This commit is contained in:
@@ -7,6 +7,10 @@ Successful responses are JSON unless marked Markdown. Errors are
|
||||
`{"error":"message"}`. Data endpoints require authentication: **401** without
|
||||
a valid session, **404** for another user's private record, **403** for
|
||||
non-admin administration, **400** for invalid input, **409** for duplicates.
|
||||
Request bodies over 1 MiB answer **413**. Rate-limited endpoints answer **429**
|
||||
with `Retry-After`; public bookmark lookups are limited per effective client
|
||||
and per bookmark id, and previews per client. Share recipient lists are
|
||||
capped (100 per bookmark/tag/collection share, 200 per shared date).
|
||||
|
||||
## Authentication
|
||||
|
||||
@@ -17,19 +21,19 @@ non-admin administration, **400** for invalid input, **409** for duplicates.
|
||||
| POST | `/api/signup` | 201 `{ok:true}` — the same uniform body for fresh, duplicate and operator-reserved addresses (review CR-03: no existence oracle); body `{email,password,name?}` |
|
||||
| POST | `/api/auth/login` | `{ok:true,user:{id,name,email,image,role}}` and signed HttpOnly cookie |
|
||||
| GET | `/api/auth/session` | `{user}` or `null` for no valid cookie |
|
||||
| POST | `/api/auth/signout` | `{ok:true}` and expired cookie |
|
||||
| POST | `/api/auth/signout` | `{ok:true}` and expired cookie; same-origin `Origin` required when present |
|
||||
| GET | `/api/me` | `{user,effectiveUser,isAdmin,viewingAs}`; real and effective identities |
|
||||
| GET | `/api/auth/oidc/status` | `{enabled,issuerSet,clientIdSet,clientSecretSet,issuer}`; never includes secrets |
|
||||
| GET | `/api/auth/oidc/status` | `{enabled,issuerSet,clientIdSet,clientSecretSet}`; never includes secrets or the issuer URL |
|
||||
| GET | `/api/auth/oidc/login` | **501**, client-owned Authelia integration stub |
|
||||
| GET, POST | `/api/auth/callback/authelia` | **501**, client-owned callback stub |
|
||||
|
||||
The browser's NextAuth `/api/auth/*` endpoints remain on the Next server.
|
||||
Direct Go API consumers use the `computer_session` cookie from login.
|
||||
Go login accepts JSON and rejects foreign browser origins. The custom Next.js
|
||||
login endpoint also requires the configured same-origin `Origin` header.
|
||||
Login and signup are throttled per client IP (429 with `Retry-After`), plus a
|
||||
consecutive-failure lockout per IP+email on login; loopback clients are
|
||||
exempt. Browser traffic arrives through the trusted Next proxy, which
|
||||
Go login accepts JSON and rejects foreign browser origins. Login and signup
|
||||
are throttled per client IP (429 with `Retry-After`), plus a
|
||||
consecutive-failure lockout per IP+email on login. Login applies to every
|
||||
peer, loopback included; signup exempts only a direct loopback peer. Browser
|
||||
traffic arrives through the trusted Next proxy, which
|
||||
forwards the observed client IP in `X-Computer-Client-Ip` signed with
|
||||
HMAC-SHA256 under the shared secret (`X-Computer-Client-Sig`); Go buckets on
|
||||
that identity only when the signature verifies and falls back to the direct
|
||||
@@ -50,10 +54,12 @@ Bookmark responses are permission-specific. Owners receive camelCase scalar
|
||||
fields plus `tags:[{tag}]`, `contact`, `sharedWith:[{userId,user}]` and
|
||||
`owner` (with email). Authenticated shared readers receive a narrowed
|
||||
allowlist — URL, title/description, notes, preview metadata, `dueDate`,
|
||||
`isPublic`, `kanbanStatus`, timestamps, `tags` and `owner:{id,name}` — never
|
||||
the owner's contact record, the recipient list, alerts, mailbox watches or
|
||||
board placement. Detail responses also include `pageLinks:[{pageId,page}]`,
|
||||
limited to the effective user's pages.
|
||||
`isPublic`, timestamps, `tags` and `owner:{id,name}` — never the owner's
|
||||
contact record, the recipient list, alerts, mailbox watches or board
|
||||
placement (`kanbanColumnId`/`kanbanPosition`). The legacy `kanbanStatus`
|
||||
badge IS included and is status, not placement; it is documented here so the
|
||||
projection and UI agree. Detail responses also include
|
||||
`pageLinks:[{pageId,page}]`, limited to the effective user's pages.
|
||||
|
||||
| Method | Path | Returns / behavior |
|
||||
|---|---|---|
|
||||
@@ -231,7 +237,7 @@ already see.
|
||||
| POST | `/api/imap/test` | `{ok:true}` after real connection/login; same mailbox fields and port rules |
|
||||
| GET | `/api/imap/check` | `{matches:[{bookmarkId,title,from,externalId,occurredAt}]}` for legacy watchers; if a search fails after finding matches, the partial `matches` are returned with an `error` field |
|
||||
| GET | `/api/shared-dates` | Created/received dates with `creator` and `recipient` |
|
||||
| POST | `/api/shared-dates` | 201 array of created shares for `{date,note?,recipientIds:[...]}` |
|
||||
| POST | `/api/shared-dates` | 201 array of created shares for `{date,note?,recipientIds:[...]}`. Sharing a date also grants read-only access to the creator's bookmarks due that day (including notes); the UI discloses this. Re-sharing the same date updates its note. |
|
||||
| DELETE | `/api/shared-dates/{id}` | `{ok:true}`, creator only |
|
||||
| GET | `/api/users/search?q=...` | Safe user projections; minimum two characters, maximum ten results |
|
||||
|
||||
|
||||
Reference in New Issue
Block a user