This repository has no description
2.9 kB
81 lines
1let
2 domain = "covibe.lassul.us";
3 port = 8770;
4in
5{
6 config,
7 pkgs,
8 self,
9 ...
10}:
11{
12 # covibe: co-vibing dashboard. Launches omp sessions in herdr as the
13 # pairprogramming user, shows live sessions + collab QR codes, and exposes a
14 # REST API. Browser auth via the local pocket-id IdP (id.lassul.us); the REST
15 # surface additionally accepts a generated API key. Collab uses omp's native
16 # stack against a self-hosted relay + self-hosted collab-web (no my.omp.sh).
17 imports = [ self.inputs.covibe.nixosModules.default ];
18
19 # Cookie-signing secret + REST API key (generated), plus the pocket-id client
20 # secret (prompted once), materialised into one EnvironmentFile:
21 # COVIBE_COOKIE_SECRET, COVIBE_API_KEYS, COVIBE_OIDC_CLIENT_SECRET.
22 clan.core.vars.generators.covibe = {
23 files."env" = { };
24 files."api_key" = { }; # readable copy of the key for clients
25 prompts.oidc_client_secret = {
26 description = "pocket-id OIDC client secret for covibe";
27 type = "hidden";
28 persist = true;
29 };
30 runtimeInputs = [ pkgs.openssl ];
31 script = ''
32 ck=$(openssl rand -hex 32)
33 ak=$(openssl rand -hex 32)
34 cs=$(cat "$prompts"/oidc_client_secret)
35 printf '%s' "$ak" > "$out/api_key"
36 printf 'COVIBE_COOKIE_SECRET=%s\nCOVIBE_API_KEYS=%s\nCOVIBE_OIDC_CLIENT_SECRET=%s\n' \
37 "$ck" "$ak" "$cs" > "$out/env"
38 '';
39 };
40
41 services.covibe = {
42 enable = true;
43 user = "pairprogramming";
44 relayHost = domain;
45 dashboard = {
46 addr = "127.0.0.1:${toString port}";
47 workspaceRoot = "/home/pairprogramming/covibe";
48 environmentFile = config.clan.core.vars.generators.covibe.files."env".path;
49 # Without an admin nobody can manage any session: sessions registered
50 # through the keyless announce API have no owner, so canManage is false
51 # for every one of them and the dashboard hides its share/kill controls.
52 admins = [ "lass@lassul.us" ];
53 oidc = {
54 issuer = "https://id.lassul.us";
55 clientId = "a7e4b0aa-f09d-472a-965b-908cd4634f16";
56 redirectUrl = "https://${domain}/auth/callback";
57 };
58 };
59 };
60
61 services.nginx.virtualHosts.${domain} = {
62 enableACME = true;
63 forceSSL = true;
64 # Collab relay websockets (/r/<roomId>) are long-lived and idle between
65 # turns; neither the relay nor omp send keepalive pings, so nginx's default
66 # 60s proxy_read_timeout would sever idle sessions and trigger omp's
67 # "connection lost, reconnecting" loop. Give the relay a long idle window.
68 locations."/r/" = {
69 proxyPass = "http://127.0.0.1:${toString port}";
70 proxyWebsockets = true;
71 extraConfig = ''
72 proxy_read_timeout 1d;
73 proxy_send_timeout 1d;
74 '';
75 };
76 locations."/" = {
77 proxyPass = "http://127.0.0.1:${toString port}";
78 proxyWebsockets = true;
79 };
80 };
81}