10 KiB
Sanitized detailed source transcription S09, captured 2026-10-24. Original planning steps, acceptance criteria and historical evidence are retained rather than condensed. Read current context and precedence first: dated holds, approvals, test counts and “latest” labels below belong to their original checkpoint and do not grant current execution/publication authority. Privacy replacements preserve roles and test semantics. See section coverage.
Public guest IndeeHub — security architecture and acceptance gate
Requirement A13, task T29. Newly required by operator: an externally shared IndeeHub link serves outside visitors without granting ANY owner Archipelago authority. This is implementation scope, NOT permission to expose a live node or change DNS/firewall/TLS now. External exposure requires separate approval after the security gate. No claim of absolute exploit-proof security is possible.
User contract
Outside visitors can open the public film catalog/details and view free content, or pay with supported external wallets and recover their own access. They do not need the publisher's Archipelago login or wallet. Signed-in owner privileges never accompany a shared URL. Decide visitor-owned identity/sign-in and cross-device receipt recovery explicitly, not by silently borrowing the publisher's identity.
Preserve original film details/player/zap amount UX, but guest-only capabilities. "Pay with my node" must not point at the serving owner's node. Disable/hide unavailable owner-native rails with useful explanation; external Lightning/on-chain and visitor-controlled ecash only if a reviewed client/token path exists. Guest continuous ecash streaming needs a separate visitor-owned bounded payer protocol; until implemented, disable it rather than using the owner wallet or claiming external QR supports automatic chunk debits. No owner browser wallet or signer is a guest dependency. Public/guest capability responses expose only intentionally offered rails; unavailable producer-side rails say “Not offered” and must not reveal whether the producer has an Archipelago wallet, any wallet/backend at all, configuration, provider, balance, health or the reason for non-offer.
Required boundary
- Separate public origin and guest application context. Prefer a dedicated registrable domain where feasible; assess same-site cookie/CSRF risk if using a subdomain. No shared owner cookies/local storage/service worker scope, broad parent-domain cookies, owner session bootstrap or app-gate auto-login. Owner/admin UI never served through the public origin. Dedicated visitor session cookie is host-only, Secure/HttpOnly with reviewed SameSite policy; it carries guest authority only.
- Explicit deny-by-default public gateway. Allowlist only reviewed catalog/detail/guest quote/invoice/status/receipt redemption/entitled playback routes plus optional reviewed visitor social flows. No generic RPC, proxy, app-launch/app-gate, WebSocket dispatch, native bridge, signer, wallet administration, filesystem, Cloud, Backstage, relay admin, metrics/config/debug endpoints or dashboard. Same backend functions still enforce principal/resource/action authorization; routing alone is not the security boundary.
- No privilege inheritance. Guest credentials/tokens are bound to guest principal, intended audience, film/media revision and entitlement/action with narrow lifetime and revocation. Reject owner cookies/tokens presented to guest-only endpoints; owner APIs reject guest tokens. No wildcard CORS/credential reflection or permissive postMessage. No external origin may obtain native wallet/signing permission through an embedded owner app or malicious message.
- Keys and private data never leave authority boundaries. No owner Nostr/private wallet keys, Cashu proofs, privileged bearer tokens, recovery phrases, API credentials or native signer prompts in public payloads/assets/logs/errors. Public creator receiving destination and signed listing are deliberately public metadata, not permission to spend/sign/manage. Guest sign-in, if provided, uses guest-controlled signing and binds verified challenges to origin/session with replay protection; public signatures are not owner authentication.
- External guest payments and recovery. Create a guest-bound durable order before an invoice/address; bind creator/amount/network/film/terms, deduplicate retries and verify authoritative settlement. Do not accept "I paid", a txid alone, arbitrary webhook or amount-match as ownership proof. Unique order/recovery capability, expiration and enumeration resistance; query tokens must not leak to logs/referrers/analytics/history. Define secure capability exchange and cross-device recovery explicitly. Pending/unknown blocks reissue/switch until resolved. Prevent reuse of another visitor's receipt and prohibit refunds/payouts by guests.
- Media authorization remains mandatory. Every manifest/range/segment/key/cache/replica request verifies the guest entitlement; no unprotected originals or object-store URLs. Browser-to-serving-node HTTPS is allowed presentation; all inter-node film fetching still uses authenticated FIPS, never fallback. CDN/proxy caching cannot leak paid/private responses between guests. Pin film identity, revision, recipient and origin; reject signed URL/redirect host substitution.
- Public social actions are visitor-owned. Published comments/likes/zaps carry visitor identity/appropriate rail receipt, not owner signatures. Protect against replay/spam/impersonation, limit size/depth/rates and sanitize rendered content. Anonymous read vs visitor signed write policy is explicit. Do not accidentally open the node's private relay through guest routes.
- Public attack surface hardening. Validate canonical paths/methods/content types/sizes; reject traversal, encoded-path bypass, Host/forwarded-header spoofing, request smuggling across proxy boundaries, redirects/open proxy/SSRF to loopback/link-local/private management and arbitrary URL fetch. Authorize redirects before following; bind trusted upstream config. Strict CSP, no unsafe rendering of metadata/comments, clickjacking/frame policy, CSRF where applicable, no cross-origin service-worker/bridge reachability. Secrets never in URLs or frontend configuration/source maps.
- Resource abuse and operational isolation. Limits for unauthenticated catalog queries, quote creation/payment polling, external invoices/addresses, socket sessions, range requests, decoding/transcoding and streaming; global and per-principal budgets/quotas/cleanup. A guest cannot trigger arbitrary owner spending, mint operations, unbounded disk/CPU/network work or internal peering. Rate limits alone are insufficient for financial authority. Logs redacted; detect abuse without storing private tokens/keys.
- Revocation and shutdown. Explicit owner opt-in to public sharing, narrow route manifest and truthful TLS/exposure status. Disable sharing without opening admin fallback or invalidating unrelated owner state; preserve paid obligations and agreed recovery policy. Patch/rollback and incident response documented. Unknown security state fails closed.
Architecture decisions before code is exposed
Record threat actors (anonymous attacker, malicious paying guest, compromised metadata producer, hostile embedded origin, replaying peer), assets/trust boundaries, payment and session sequence diagrams, route/method schemas, capability lifecycle, same-site/cookie/bridge assumptions, visitor identity/recovery policy, capacity budget and external TLS/domain ownership. Reuse existing reviewed website guest-access primitives ONLY after demonstrating they provide these boundaries; an app-wide reverse-proxy allow does not.
Adversarial acceptance (mandatory; independent reviewer)
- Two browsers/users plus anonymous context: guest cannot reach owner's wallet balances/keys/signing/administration, Backstage/drafts/private Cloud, other apps, terminal, RPC, metrics/config or private relay. Test direct URL, API, WebSocket, alternate path encoding/method/origin/Host, authenticated-owner cookie presented through public surface and vice versa.
- Cross-tenant order/receipt/media IDOR, guessed/replayed/stolen/expired/revoked/wrong-audience capabilities, amount/recipient/film substitution, forged callbacks, session fixation/login CSRF and unauthorized bridge/postMessage/signer calls rejected. Legitimate guest external checkout and recovery still work.
- Differential/enum tests compare absent, unconfigured, offline and incompatible producer wallets/backends: public status, timing, error body, headers and observable polling behavior reveal no producer wallet/provider/Archipelago-wallet state beyond the rails deliberately offered. Producer diagnostics require authenticated producer/admin authority and remain redacted.
- Malicious title/poster/URL/comment/avatar/subtitle/playlist and reflected error cases: no XSS, SSRF, path traversal, open redirect, token/referrer leakage or private cache disclosure. No unreviewed third-party script on payment/receipt pages.
- Concurrent/slow/abusive catalog, quote and media requests: bounded resources and no unintended wallet effects; owner UI/services remain healthy under declared load. No automatic spend from owner to satisfy guest demand.
- Free/paid/expired/renewed guest film through actual installed public gateway with valid TLS; every remote hop FIPS; outage preserves guest purchase and fails closed. No owner credentials present in client network/storage inspection.
- Scanner/fuzz/negative tests supplement manual independent security review; neither a clean scan nor simulated preview equals an exploit-free guarantee. Fix blockers, rerun and sign off exact public artifact/route configuration before exposure.
Deployment boundary
Public mode disabled by default until T29 acceptance. operator node private UAT may exercise disposable/local test origins first; production external route/TLS/firewall change needs explicit scoped approval and rollback. T22/T23 final acceptance and owner release require A13 evidence. Do not silently waive this requirement to meet a date; an unavailable penetration/security test is BLOCKED, not PASS.