pnpm workspace with apps/web, apps/api, apps/collab, and packages/shared; strict TypeScript base config, repo-wide ESLint (flat) + Prettier, Vitest per package, and root scripts lint/typecheck/test/ build. @dorfteich/shared ships a first health-response helper consumed by apps/api to prove workspace linking. Existing markdown docs are reformatted once by the new Prettier setup. Closes #1 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
101 lines
4.5 KiB
Markdown
101 lines
4.5 KiB
Markdown
# Security concept
|
|
|
|
Threat-driven summary; detailed mechanics live in the referenced ADRs.
|
|
|
|
## Assets & main threats
|
|
|
|
Wiki content (possibly confidential per pond/label), user credentials and
|
|
e-mail addresses, instance availability. Threat actors: anonymous internet
|
|
(public instance with self-signup), malicious registered users, malicious
|
|
or sloppy plugin authors, compromised dependencies.
|
|
|
|
## Authentication & session security (ADR 0007)
|
|
|
|
- Argon2id password hashing; opaque server-side sessions in HttpOnly,
|
|
Secure, SameSite=Lax cookies; CSRF protected by SameSite + origin checks
|
|
on mutating requests (double-submit token for the file-download edge
|
|
cases).
|
|
- E-mail verification (double opt-in) before an account can create content;
|
|
password reset via single-use hashed tokens; both rate-limited.
|
|
- Rate limiting (DB-backed) on login, signup, reset, and API; lockout
|
|
backoff on repeated failed logins per account+IP.
|
|
- Self-registration can be disabled instance-wide; personal-pond quotas
|
|
(editors/readers/ponds/storage) bound the blast radius of spam accounts.
|
|
|
|
## Authorization
|
|
|
|
- Single resolution algorithm (`permissions.md`) in `packages/shared`,
|
|
enforced in API guards and at collab token issuance — never in the client.
|
|
- Default-closed: no grant → no access. Public access is always an explicit
|
|
grant.
|
|
- Admin actions are audit-logged (`operations.md`).
|
|
|
|
## Content & upload security
|
|
|
|
- Editor content is structured (ProseMirror schema) — no raw HTML from
|
|
users. The HTML render endpoint escapes everything outside the schema;
|
|
link protocols allowlisted (`https`, `http`, `mailto`).
|
|
- Uploads (ADR 0011): MIME/extension allowlist, size limits, magic-byte
|
|
checks, SVG sanitization or rejection, `Content-Disposition: attachment`
|
|
for non-image types, no user content served same-origin as executable
|
|
(`X-Content-Type-Options: nosniff`; uploads path never serves
|
|
`text/html`).
|
|
- App CSP (strict): `default-src 'self'`; `font-src 'self'` (ADR 0016);
|
|
no third-party origins at all — the GDPR posture is "zero external
|
|
requests".
|
|
|
|
## Plugin sandboxing (ADR 0008, operational)
|
|
|
|
- Code plugins: opaque-origin iframes, no network (`connect-src 'none'`),
|
|
capability-scoped postMessage API executed with the **viewer's**
|
|
permissions server-side; declared capabilities surfaced to the Site Admin
|
|
at install time.
|
|
- Style plugins: CSS sanitized (no `@import`/external `url()`), scoped
|
|
class names.
|
|
- Install surface restricted to Site Admins; packages size-limited and
|
|
schema-validated; the `plugins/` directory watcher only trusts the volume
|
|
(host-level access implies game over anyway).
|
|
|
|
## Collaboration layer
|
|
|
|
- WebSocket connect requires a short-lived (≤ 60 s) single-purpose JWT
|
|
bound to user + page + mode; write revocation closes sessions via
|
|
LISTEN/NOTIFY (`realtime-collaboration.md`).
|
|
- Update size and document size ceilings prevent resource-exhaustion via
|
|
crafted CRDT updates.
|
|
|
|
## Secrets & configuration
|
|
|
|
- Secrets (DB password, collab signing key, SMTP credentials) live only in
|
|
the stage `.env` (mode 600, never in git) and container env — not in the
|
|
database (`instance_settings` stores non-secret config; the SMTP password
|
|
entered in the setup wizard is written to the env-backed secret store,
|
|
not to a DB row).
|
|
- Key rotation: collab signing key and session pepper rotate via env change
|
|
plus rolling restart; procedure documented in `operations.md` runbooks.
|
|
- Dependencies: lockfile-pinned; monthly update batch; images pinned to
|
|
digests in Prod.
|
|
|
|
## Privacy (GDPR)
|
|
|
|
- No external requests from the browser (fonts self-hosted, no CDNs, no
|
|
analytics by default).
|
|
- Instance-configurable legal pages (imprint, privacy policy) are a core
|
|
feature; dorfteich.online uses the operator's standard texts.
|
|
- Data minimization: username, e-mail, password hash, locale — nothing
|
|
else required. Account deletion: personal pond and authored ponds
|
|
follow the trash/purge path; authorship on shared content is pseudonymized
|
|
("deleted user"). A data-export endpoint (own profile + own ponds as
|
|
Markdown/ZIP) supports access/portability requests.
|
|
- IP addresses appear only in rate-limit counters (short TTL) and reverse
|
|
proxy logs (host-level rotation) — documented in the privacy-policy
|
|
template.
|
|
|
|
## Out of scope (v1, explicit)
|
|
|
|
- No end-to-end encryption of page content (server sees plaintext — needed
|
|
for search, export, rendering).
|
|
- No plugin marketplace/signing — installation is a deliberate Site Admin
|
|
act of trust in the reviewed package.
|
|
- No SSO in MVP (OIDC-ready per ADR 0007).
|