···11type response = {token: string} [@@deriving yojson {strict= false}]
2233let handler =
44- Xrpc.handler ~auth:Authorization (fun {req; auth; db} ->
44+ Xrpc.handler ~auth:Authorization (fun {req; auth; db; _} ->
55 let did = Auth.get_authed_did_exn auth in
66 let aud, lxm =
77 match (Dream.query req "aud", Dream.query req "lxm") with
+117-23
pegasus/lib/data_store.ml
···3636 created_at INTEGER NOT NULL,
3737 deactivated_at INTEGER
3838 )
3939- |sql}]
3939+ |sql}]
4040 () conn
4141 in
4242 let$! () =
···5252 [%rapper
5353 execute
5454 {sql| CREATE TABLE IF NOT EXISTS invite_codes (
5555- code TEXT PRIMARY KEY,
5656- did TEXT NOT NULL,
5757- remaining INTEGER NOT NULL
5858- )
5959- |sql}]
5555+ code TEXT PRIMARY KEY,
5656+ did TEXT NOT NULL,
5757+ remaining INTEGER NOT NULL
5858+ )
5959+ |sql}]
6060 () conn
6161 in
6262 let$! () =
6363 [%rapper
6464 execute
6565 {sql| CREATE TABLE IF NOT EXISTS firehose (
6666- seq INTEGER PRIMARY KEY,
6767- time INTEGER NOT NULL,
6868- t TEXT NOT NULL,
6969- data BLOB NOT NULL
7070- )
7171- |sql}]
6666+ seq INTEGER PRIMARY KEY,
6767+ time INTEGER NOT NULL,
6868+ t TEXT NOT NULL,
6969+ data BLOB NOT NULL
7070+ )
7171+ |sql}]
7272 () conn
7373 in
7474- [%rapper
7575- execute
7676- (* no need to store issued tokens, just revoked ones; stolen from millipds https://github.com/DavidBuchanan314/millipds/blob/8f89a01e7d367a2a46f379960e9ca50347dcce71/src/millipds/database.py#L253 *)
7777- {sql| CREATE TABLE IF NOT EXISTS revoked_tokens (
7878- did TEXT NOT NULL,
7979- jti TEXT NOT NULL,
8080- revoked_at INTEGER NOT NULL,
8181- PRIMARY KEY (did, jti)
8282- )
8383- |sql}]
8484- () conn
7474+ let$! () =
7575+ [%rapper
7676+ execute
7777+ (* no need to store issued tokens, just revoked ones; stolen from millipds https://github.com/DavidBuchanan314/millipds/blob/8f89a01e7d367a2a46f379960e9ca50347dcce71/src/millipds/database.py#L253 *)
7878+ {sql| CREATE TABLE IF NOT EXISTS revoked_tokens (
7979+ did TEXT NOT NULL,
8080+ jti TEXT NOT NULL,
8181+ revoked_at INTEGER NOT NULL,
8282+ PRIMARY KEY (did, jti)
8383+ )
8484+ |sql}]
8585+ () conn
8686+ in
8787+ let$! () =
8888+ [%rapper
8989+ execute
9090+ {sql| CREATE TABLE IF NOT EXISTS oauth_requests (
9191+ request_id TEXT PRIMARY KEY,
9292+ client_id TEXT NOT NULL,
9393+ request_data TEXT NOT NULL,
9494+ dpop_jkt TEXT,
9595+ expires_at INTEGER NOT NULL,
9696+ created_at INTEGER NOT NULL
9797+ )
9898+ |sql}]
9999+ () conn
100100+ in
101101+ let$! () =
102102+ [%rapper
103103+ execute
104104+ {sql| CREATE TABLE IF NOT EXISTS oauth_codes (
105105+ code TEXT PRIMARY KEY,
106106+ request_id TEXT NOT NULL REFERENCES oauth_requests(request_id),
107107+ authorized_by TEXT,
108108+ authorized_at INTEGER,
109109+ expires_at INTEGER NOT NULL,
110110+ used BOOLEAN DEFAULT FALSE
111111+ )
112112+ |sql}]
113113+ () conn
114114+ in
115115+ let$! () =
116116+ [%rapper
117117+ execute
118118+ {sql| CREATE TABLE IF NOT EXISTS oauth_tokens (
119119+ id INTEGER PRIMARY KEY,
120120+ token_id TEXT UNIQUE NOT NULL,
121121+ refresh_token TEXT UNIQUE NOT NULL,
122122+ client_id TEXT NOT NULL,
123123+ did TEXT NOT NULL,
124124+ dpop_jkt TEXT,
125125+ scope TEXT NOT NULL,
126126+ created_at INTEGER NOT NULL,
127127+ expires_at INTEGER NOT NULL,
128128+ last_refreshed_at INTEGER NOT NULL
129129+ )
130130+ |sql}]
131131+ () conn
132132+ in
133133+ let$! () =
134134+ [%rapper
135135+ execute
136136+ {sql| CREATE INDEX oauth_requests_expires_idx ON oauth_requests(expires_at);
137137+ CREATE INDEX oauth_codes_expires_idx ON oauth_codes(expires_at);
138138+ CREATE INDEX oauth_tokens_refresh_idx ON oauth_tokens(refresh_token);
139139+ |sql}]
140140+ () conn
141141+ in
142142+ let$! () =
143143+ [%rapper
144144+ execute
145145+ {sql| CREATE TRIGGER IF NOT EXISTS cleanup_expired_oauth_requests
146146+ AFTER INSERT ON oauth_requests
147147+ BEGIN
148148+ DELETE FROM oauth_requests WHERE expires_at < unixepoch() * 1000;
149149+ END
150150+ |sql}
151151+ syntax_off]
152152+ () conn
153153+ in
154154+ let$! () =
155155+ [%rapper
156156+ execute
157157+ {sql| CREATE TRIGGER IF NOT EXISTS cleanup_expired_oauth_codes
158158+ AFTER INSERT ON oauth_codes
159159+ BEGIN
160160+ DELETE FROM oauth_codes WHERE expires_at < unixepoch() * 1000;
161161+ END
162162+ |sql}
163163+ syntax_off]
164164+ () conn
165165+ in
166166+ let$! () =
167167+ [%rapper
168168+ execute
169169+ {sql| CREATE TRIGGER IF NOT EXISTS cleanup_expired_oauth_tokens
170170+ AFTER INSERT ON oauth_tokens
171171+ BEGIN
172172+ DELETE FROM oauth_tokens WHERE expires_at < unixepoch() * 1000;
173173+ END
174174+ |sql}
175175+ syntax_off]
176176+ () conn
177177+ in
178178+ Lwt.return_ok ()
8517986180 let create_actor =
87181 [%rapper
+13
pegasus/lib/env.ml
···1313let jwt_key = Sys.getenv "JWK_MULTIBASE" |> Kleidos.parse_multikey_str
14141515let admin_password = Sys.getenv "ADMIN_PASSWORD"
1616+1717+let dpop_nonce_secret =
1818+ match Sys.getenv_opt "DPOP_NONCE_SECRET" with
1919+ | Some sec ->
2020+ let secret = Base64.decode_exn sec |> Bytes.of_string in
2121+ if Bytes.length secret = 32 then secret
2222+ else failwith "DPOP_NONCE_SECRET must be 32 bytes in base64"
2323+ | None ->
2424+ let secret = Mirage_crypto_rng_unix.getrandom 32 in
2525+ Dream.warning (fun log ->
2626+ log "DPOP_NONCE_SECRET not set; using DPOP_NONCE_SECRET=%s"
2727+ (Base64.encode secret |> Result.get_ok) ) ;
2828+ Bytes.of_string secret