rc), ZNC decommissioned. Remaining: replace placeholder stripe-keys, configure Upptime (needs GH token perms), remove znc.josie.lol DNS from Cloudflare. - `stripe_util.rs` (renamed from `stripe.rs` to avoid shadowing the `stripe` crate) ## Phase 3 Status Deployed and live. Two new crates: paste (txt.irc.now) and pics (irc.pics). Auth: OIDC via Keycloak, plan detection via token claims (defaults to free/None). Paste: nanoid IDs, 24h expiry for free users, 5 paste limit, hourly cleanup task. Pics: MinIO (S3) storage, thumbnails (300px WebP), 50MB free / 1GB pro storage limit. Keycloak migrated to operator-managed CR in `keycloak` namespace (was manual Deployment in `irc-keycloak`). Custom irc-now login theme deployed via ConfigMap + init container. Logout redirect fixed: derives origin from OIDC_REDIRECT_URL, post-logout URIs configured in Keycloak clients. - `rust-s3 = "0.35"` for S3 client - `image = "0.25"` for thumbnail generation - Axum route ordering: static routes (`/my`) must precede parameterized (`/{id}`) - SameSite::Lax required on session cookies for cross-site OIDC redirects ## Chat Service (chat.irc.now) gamja web IRC client served by nginx. Top-level `chat/` directory (not a Rust crate). - Containerfile clones gamja from `git.sr.ht/~emersion/gamja` (codeberg mirror unreliable) - nginx serves static files, proxies `/socket` to soju WebSocket (`josie:8080`) - `proxy_set_header Host $host;` required so soju's WebSocket Origin check passes - Theme injected via nginx `sub_filter` on `` tag (AGPL compliance) - Title renamed via `sub_filter 'gamja IRC client' 'chat.irc.now'` - soju-operator supports `websocket: bool` on Listener type (`ws+insecure://`, `wss://`) - OAuth2 SSO: gamja -> Keycloak (public client `chat`) -> SASL OAUTHBEARER -> soju - soju `auth oauth2` with `enable-user-on-auth true`, credentials from `oidc-soju` secret - Keycloak `chat` client: PKCE disabled (gamja doesn't support it), `exclude.session.state.from.auth.response` and `exclude.issuer.from.auth.response` set to avoid redirect_uri mismatch - Build: `oc start-build chat --from-dir=chat/ -n irc-josie-cloud --follow` - Route has `haproxy.router.openshift.io/timeout: 600s` for WebSocket keepalive ## Whois Hostname Cloaking (Deployed) Design: docs/plans/2026-03-05-whois-hostname-cloaking-design.md Plan: docs/plans/2026-03-05-whois-hostname-cloaking-plan.md - CRD has `hostname_cloak: Option`, operator emits `hostname-cloak` in soju.conf - Custom soju image at `crates/soju-operator/soju/` (Containerfile + apply-hostname-cloak.sh) - Containerfile clones from Codeberg master, applies hostname-cloak sed patch, builds with nosqlite - SOJU_IMAGE = internal registry, imagePullPolicy = Always - All bouncer CRs patched with `hostname_cloak: .irc.now` - web-api sets hostname_cloak on bouncer creation - Cloaking applies to **downstream** connections (clients connecting to soju bouncer) - Does NOT affect upstream network whois (hackint etc. show soju server IP) - Next: rDNS or network-level cloaks needed for upstream whois ## Ergo Operator (net.irc.now) - CRD: ErgoNetwork (`irc.josie.cloud/v1alpha1`), manages Ergo IRC server instances - Image: `ghcr.io/ergochat/ergo:stable` - Config mounted at `/config/ircd.yaml`, TLS at `/config/tls/` - Ergo config: `listeners` must be nested under `server:` (not top-level) - Previous serde_yaml serialization put `listeners` at top level, causing crash - Fixed by manual YAML string generation in `configmap.rs` - OAuth2 token introspection via Keycloak (`oidc-ergo` secret) - IP cloaking configured per-network via `spec.cloaking.netname` - Storage: 1Gi PVC (`customer-workload-storage`) for ircd.db ## Soju Version Notes - Primary repo: Codeberg (codeberg.org/emersion/soju) -- GitHub/SourceHut are stale mirrors - No v0.10.x tags; Go module proxy serves pseudo-versions for tagged releases only - Codeberg master has schema v20 (20 PostgreSQL migrations) - Custom image builds from Codeberg master via `git clone` in Containerfile - `nosqlite` build tag required for CGO_ENABLED=0 builds (we use PostgreSQL) - imagePullPolicy must be Always since we use :latest tag ## Obsidian Docs Service notes at ~/Documents/Obsidian Vault/98 josiedot/services/: - irc-now-landing.md, irc-now-portal.md, irc-now-keycloak.md, irc-bot-landing.md - irc-now-chat.md, irc-now-txt.md, irc-now-pics.md, irc-now-soju-operator.md - irc-now-ergo-operator.md