let domain = "covibe.lassul.us"; port = 8770; in { config, pkgs, self, ... }: { # covibe: co-vibing dashboard. Launches omp sessions in herdr as the # pairprogramming user, shows live sessions + collab QR codes, and exposes a # REST API. Browser auth via the local pocket-id IdP (id.lassul.us); the REST # surface additionally accepts a generated API key. Collab uses omp's native # stack against a self-hosted relay + self-hosted collab-web (no my.omp.sh). imports = [ self.inputs.covibe.nixosModules.default ]; # Cookie-signing secret + REST API key (generated), plus the pocket-id client # secret (prompted once), materialised into one EnvironmentFile: # COVIBE_COOKIE_SECRET, COVIBE_API_KEYS, COVIBE_OIDC_CLIENT_SECRET. clan.core.vars.generators.covibe = { files."env" = { }; files."api_key" = { }; # readable copy of the key for clients prompts.oidc_client_secret = { description = "pocket-id OIDC client secret for covibe"; type = "hidden"; persist = true; }; runtimeInputs = [ pkgs.openssl ]; script = '' ck=$(openssl rand -hex 32) ak=$(openssl rand -hex 32) cs=$(cat "$prompts"/oidc_client_secret) printf '%s' "$ak" > "$out/api_key" printf 'COVIBE_COOKIE_SECRET=%s\nCOVIBE_API_KEYS=%s\nCOVIBE_OIDC_CLIENT_SECRET=%s\n' \ "$ck" "$ak" "$cs" > "$out/env" ''; }; services.covibe = { enable = true; user = "pairprogramming"; relayHost = domain; dashboard = { addr = "127.0.0.1:${toString port}"; workspaceRoot = "/home/pairprogramming/covibe"; environmentFile = config.clan.core.vars.generators.covibe.files."env".path; # Without an admin nobody can manage any session: sessions registered # through the keyless announce API have no owner, so canManage is false # for every one of them and the dashboard hides its share/kill controls. admins = [ "lass@lassul.us" ]; oidc = { issuer = "https://id.lassul.us"; clientId = "a7e4b0aa-f09d-472a-965b-908cd4634f16"; redirectUrl = "https://${domain}/auth/callback"; }; }; }; services.nginx.virtualHosts.${domain} = { enableACME = true; forceSSL = true; # Collab relay websockets (/r/) are long-lived and idle between # turns; neither the relay nor omp send keepalive pings, so nginx's default # 60s proxy_read_timeout would sever idle sessions and trigger omp's # "connection lost, reconnecting" loop. Give the relay a long idle window. locations."/r/" = { proxyPass = "http://127.0.0.1:${toString port}"; proxyWebsockets = true; extraConfig = '' proxy_read_timeout 1d; proxy_send_timeout 1d; ''; }; locations."/" = { proxyPass = "http://127.0.0.1:${toString port}"; proxyWebsockets = true; }; }; }