···22 Xrpc.handler ~auth:Authorization (fun {auth; db; _} ->
33 let did = Auth.get_authed_did_exn auth in
44 let code = Util.make_code () in
55- let expires_at = Util.now_ms () + (60 * 60 * 1000) in
55+ let expires_at = Util.Time.now_ms () + (60 * 60 * 1000) in
66 let%lwt () = Data_store.set_auth_code ~did ~code ~expires_at db in
77 let%lwt {email; handle; _} =
88 Data_store.get_actor_by_identifier did db |> Lwt.map Option.get
+2-2
pegasus/lib/api/identity/signPlcOperation.ml
···1313 | Some actor -> (
1414 match (actor.auth_code, actor.auth_code_expires_at) with
1515 | auth_code, Some auth_expires_at
1616- when input.token = auth_code && Util.now_ms () < auth_expires_at -> (
1616+ when input.token = auth_code && Util.Time.now_ms () < auth_expires_at -> (
1717 match%lwt Plc.get_audit_log did with
1818 | Ok log ->
1919 let latest = Mist.Util.last log |> Option.get in
···2121 Option.map
2222 (fun v ->
2323 try
2424- Util.Did_doc_types.string_map_of_yojson v |> Result.get_ok
2424+ Util.Types.string_map_of_yojson v |> Result.get_ok
2525 with _ -> Errors.invalid_request "invalid request body" )
2626 input.verification_methods
2727 in
+4-85
pegasus/lib/api/identity/updateHandle.ml
···11open Lexicons.Com.Atproto.Identity.UpdateHandle.Main
2233-type update_handle_error =
44- | InvalidFormat of string
55- | HandleTaken
66- | TooShort of string
77- | TooLong of string
88- | InternalServerError of string
99-1010-let update_handle_error_to_string = function
1111- | InvalidFormat m | TooShort m | TooLong m ->
1212- "handle " ^ m
1313- | HandleTaken ->
1414- "handle already taken"
1515- | InternalServerError msg ->
1616- msg
1717-1818-let update_handle ~did ~handle db =
1919- match Util.validate_handle handle with
2020- | Error (InvalidFormat e) ->
2121- Lwt.return_error (InvalidFormat e)
2222- | Error (TooShort e) ->
2323- Lwt.return_error (TooShort e)
2424- | Error (TooLong e) ->
2525- Lwt.return_error (TooLong e)
2626- | Ok () -> (
2727- match%lwt Data_store.get_actor_by_identifier handle db with
2828- | Some _ ->
2929- Lwt.return_error HandleTaken
3030- | None -> (
3131- let%lwt {handle= prev_handle; _} =
3232- Data_store.get_actor_by_identifier did db |> Lwt.map Option.get
3333- in
3434- let%lwt () = Data_store.update_actor_handle ~did ~handle db in
3535- let%lwt plc_result =
3636- if String.starts_with ~prefix:"did:plc:" did then
3737- match%lwt Plc.get_audit_log did with
3838- | Error e ->
3939- Lwt.return_error
4040- (InternalServerError ("failed to fetch did doc: " ^ e))
4141- | Ok log -> (
4242- let latest = List.rev log |> List.hd in
4343- let aka =
4444- match
4545- List.mem ("at://" ^ handle) latest.operation.also_known_as
4646- with
4747- | true ->
4848- latest.operation.also_known_as
4949- | false ->
5050- ("at://" ^ handle) :: latest.operation.also_known_as
5151- in
5252- let aka =
5353- List.filter (fun x -> x <> "at://" ^ prev_handle) aka
5454- in
5555- let signed =
5656- Plc.sign_operation Env.rotation_key
5757- (Operation
5858- { type'= "plc_operation"
5959- ; prev= Some latest.cid
6060- ; also_known_as= aka
6161- ; rotation_keys= latest.operation.rotation_keys
6262- ; verification_methods=
6363- latest.operation.verification_methods
6464- ; services= latest.operation.services } )
6565- in
6666- match%lwt Plc.submit_operation did signed with
6767- | Ok _ ->
6868- Lwt.return_ok ()
6969- | Error (status, msg) ->
7070- Lwt.return_error
7171- (InternalServerError
7272- (Printf.sprintf "failed to submit plc operation: %d %s"
7373- status msg ) ) )
7474- else Lwt.return_ok ()
7575- in
7676- match plc_result with
7777- | Error e ->
7878- Lwt.return_error e
7979- | Ok () ->
8080- let () = Ttl_cache.String_cache.remove Id_resolver.Did.cache did in
8181- let%lwt _ = Sequencer.sequence_identity db ~did ~handle () in
8282- Lwt.return_ok () ) )
8383-843let calc_key_did ctx = Some (Auth.get_authed_did_exn ctx.Xrpc.auth)
854865let handler =
876 Xrpc.handler ~auth:Authorization
887 ~rate_limits:
898 [ Route
9090- { duration_ms= 5 * Util.minute
99+ { duration_ms= 5 * Util.Time.minute
9110 ; points= 10
9211 ; calc_key= Some calc_key_did
9312 ; calc_points= None }
9413 ; Route
9595- { duration_ms= Util.day
1414+ { duration_ms= Util.Time.day
9615 ; points= 50
9716 ; calc_key= Some calc_key_did
9817 ; calc_points= None } ]
···10019 Auth.assert_identity_scope auth ~attr:Oauth.Scopes.Handle ;
10120 let did = Auth.get_authed_did_exn auth in
10221 let%lwt {handle} = Xrpc.parse_body req input_of_yojson in
103103- match%lwt update_handle ~did ~handle db with
2222+ match%lwt Identity_util.update_handle ~did ~handle db with
10423 | Ok () ->
10524 Dream.empty `OK
10625 | Error e ->
107107- let msg = update_handle_error_to_string e in
2626+ let msg = Identity_util.update_handle_error_to_string e in
10827 Log.err (fun log -> log "%s" msg) ;
10928 Errors.invalid_request ~name:"InvalidHandle" msg )
+4-4
pegasus/lib/api/oauth_/authorize.ml
···44let get_handler =
55 Xrpc.handler (fun ctx ->
66 let login_redirect =
77- Uri.make ~path:"/account/login" ~query:(Util.copy_query ctx.req) ()
77+ Uri.make ~path:"/account/login" ~query:(Util.Http.copy_query ctx.req) ()
88 |> Uri.to_string |> Dream.redirect ctx.req
99 in
1010 let client_id = Dream.query ctx.req "client_id" in
···4545 ^ Uuidm.to_string
4646 (Uuidm.v4_gen (Random.State.make_self_init ()) ())
4747 in
4848- let expires_at = Util.now_ms () + Constants.code_expiry_ms in
4848+ let expires_at = Util.Time.now_ms () + Constants.code_expiry_ms in
4949 let%lwt () =
5050 Queries.insert_auth_code ctx.db
5151 { code
···136136 Option.value current_user
137137 ~default:(List.hd logged_in_users)
138138 in
139139- Util.render_html ~title:("Authorizing " ^ host)
139139+ Util.Html.render_page ~title:("Authorizing " ^ host)
140140 (module Frontend.OauthAuthorizePage)
141141 ~props:
142142 { client_url
···191191 Errors.invalid_request "code already authorized"
192192 else if code_rec.used then
193193 Errors.invalid_request "code already used"
194194- else if Util.now_ms () > code_rec.expires_at then
194194+ else if Util.Time.now_ms () > code_rec.expires_at then
195195 Errors.invalid_request "code expired"
196196 else if code_rec.request_id <> request_id then
197197 Errors.invalid_request "code not for this request"
+2-2
pegasus/lib/api/oauth_/par.ml
···2323 ^ Uuidm.to_string (Uuidm.v4_gen (Random.State.make_self_init ()) ())
2424 in
2525 let request_uri = Constants.request_uri_prefix ^ request_id in
2626- let expires_at = Util.now_ms () + Constants.par_request_ttl_ms in
2626+ let expires_at = Util.Time.now_ms () + Constants.par_request_ttl_ms in
2727 let request : oauth_request =
2828 { request_id
2929 ; client_id= req.client_id
3030 ; request_data= Yojson.Safe.to_string (par_request_to_yojson req)
3131 ; dpop_jkt= Some proof.jkt
3232 ; expires_at
3333- ; created_at= Util.now_ms () }
3333+ ; created_at= Util.Time.now_ms () }
3434 in
3535 let%lwt () = Queries.insert_par_request ctx.db request in
3636 Dream.json ~status:`Created
+2-2
pegasus/lib/api/oauth_/token.ml
···1717 | None ->
1818 Errors.invalid_request "invalid code"
1919 | Some code_rec -> (
2020- if Util.now_ms () > code_rec.expires_at then
2020+ if Util.Time.now_ms () > code_rec.expires_at then
2121 Errors.invalid_request "code expired"
2222 else
2323 match code_rec.authorized_by with
···8080 () )
8181 in
8282 let now_sec = int_of_float (Unix.gettimeofday ()) in
8383- let now_ms = Util.now_ms () in
8383+ let now_ms = Util.Time.now_ms () in
8484 let expires_in =
8585 Constants.access_token_expiry_ms / 1000
8686 in
+1-1
pegasus/lib/api/proxy/appBskyFeedGetFeed.ml
···77let handler =
88 Xrpc.handler ~auth:Authorization (fun ctx ->
99 let input = Xrpc.parse_query ctx.req query_of_yojson in
1010- match Util.parse_at_uri input.feed with
1010+ match Util.Syntax.parse_at_uri input.feed with
1111 | None ->
1212 Errors.invalid_request ("invalid feed URI " ^ input.feed)
1313 | Some {repo; collection; rkey; _} -> (
+2-2
pegasus/lib/api/repo/getRecord.ml
···99 match input_did with
1010 | Ok input_did -> (
1111 let uri =
1212- Util.make_at_uri ~repo:input_did ~collection:input.collection
1212+ Util.Syntax.make_at_uri ~repo:input_did ~collection:input.collection
1313 ~rkey:input.rkey ~fragment:None
1414 in
1515 let%lwt repo = Repository.load ~ensure_active:true input_did in
···6868 Errors.internal_error ~name:"RecordNotFound"
6969 ~msg:
7070 ( "could not find record "
7171- ^ Util.make_at_uri ~repo:input.repo ~collection:input.collection
7171+ ^ Util.Syntax.make_at_uri ~repo:input.repo ~collection:input.collection
7272 ~rkey:input.rkey ~fragment:None )
7373 () ) )
···88 let uri =
99 Uri.of_string ("https://" ^ handle ^ "/.well-known/atproto-did")
1010 in
1111- let%lwt {status; _}, body = Util.http_get uri in
1111+ let%lwt {status; _}, body = Util.Http.get uri in
1212 match status with
1313 | `OK ->
1414 let%lwt did = Body.to_string body in
···7777end
78787979module Did = struct
8080- open Util.Did_doc_types
8080+ open Util.Types
81818282 module Document = struct
8383 type service =
···175175 ~path:(Uri.pct_encode did) ()
176176 in
177177 let%lwt {status; _}, body =
178178- Util.http_get uri
178178+ Util.Http.get uri
179179 ~headers:(Cohttp.Header.of_list [("Accept", "application/json")])
180180 in
181181 match status with
···197197 ~path:"/.well-known/did.json" ()
198198 in
199199 let%lwt {status; _}, body =
200200- Util.http_get uri
200200+ Util.Http.get uri
201201 ~headers:(Cohttp.Header.of_list [("Accept", "application/json")])
202202 in
203203 match status with
+107
pegasus/lib/identity_util.ml
···11+type validate_handle_error =
22+ | InvalidFormat of string
33+ | TooShort of string
44+ | TooLong of string
55+66+let validate_handle handle =
77+ (* if it's a custom domain, just check that it contains a period *)
88+ if not (String.ends_with ~suffix:("." ^ Env.hostname) handle) then
99+ if not (String.contains handle '.') then
1010+ Error (InvalidFormat ("must end with " ^ "." ^ Env.hostname))
1111+ else Ok ()
1212+ else
1313+ let front =
1414+ String.sub handle 0
1515+ (String.length handle - (String.length Env.hostname + 1))
1616+ in
1717+ if String.contains front '.' then
1818+ Error (InvalidFormat "can't contain periods")
1919+ else
2020+ match String.length front with
2121+ | l when l < 3 ->
2222+ Error (TooShort "must be at least 3 characters")
2323+ | l when l > 18 ->
2424+ Error (TooLong "must be at most 18 characters")
2525+ | _ ->
2626+ Ok ()
2727+2828+type update_handle_error =
2929+ | InvalidFormat of string
3030+ | HandleTaken
3131+ | TooShort of string
3232+ | TooLong of string
3333+ | InternalServerError of string
3434+3535+let update_handle_error_to_string = function
3636+ | InvalidFormat m | TooShort m | TooLong m ->
3737+ "handle " ^ m
3838+ | HandleTaken ->
3939+ "handle already taken"
4040+ | InternalServerError msg ->
4141+ msg
4242+4343+let update_handle ~did ~handle db =
4444+ match validate_handle handle with
4545+ | Error (InvalidFormat e) ->
4646+ Lwt.return_error (InvalidFormat e)
4747+ | Error (TooShort e) ->
4848+ Lwt.return_error (TooShort e)
4949+ | Error (TooLong e) ->
5050+ Lwt.return_error (TooLong e)
5151+ | Ok () -> (
5252+ match%lwt Data_store.get_actor_by_identifier handle db with
5353+ | Some _ ->
5454+ Lwt.return_error HandleTaken
5555+ | None -> (
5656+ let%lwt {handle= prev_handle; _} =
5757+ Data_store.get_actor_by_identifier did db |> Lwt.map Option.get
5858+ in
5959+ let%lwt () = Data_store.update_actor_handle ~did ~handle db in
6060+ let%lwt plc_result =
6161+ if String.starts_with ~prefix:"did:plc:" did then
6262+ match%lwt Plc.get_audit_log did with
6363+ | Error e ->
6464+ Lwt.return_error
6565+ (InternalServerError ("failed to fetch did doc: " ^ e))
6666+ | Ok log -> (
6767+ let latest = List.rev log |> List.hd in
6868+ let aka =
6969+ match
7070+ List.mem ("at://" ^ handle) latest.operation.also_known_as
7171+ with
7272+ | true ->
7373+ latest.operation.also_known_as
7474+ | false ->
7575+ ("at://" ^ handle) :: latest.operation.also_known_as
7676+ in
7777+ let aka =
7878+ List.filter (fun x -> x <> "at://" ^ prev_handle) aka
7979+ in
8080+ let signed =
8181+ Plc.sign_operation Env.rotation_key
8282+ (Operation
8383+ { type'= "plc_operation"
8484+ ; prev= Some latest.cid
8585+ ; also_known_as= aka
8686+ ; rotation_keys= latest.operation.rotation_keys
8787+ ; verification_methods=
8888+ latest.operation.verification_methods
8989+ ; services= latest.operation.services } )
9090+ in
9191+ match%lwt Plc.submit_operation did signed with
9292+ | Ok _ ->
9393+ Lwt.return_ok ()
9494+ | Error (status, msg) ->
9595+ Lwt.return_error
9696+ (InternalServerError
9797+ (Printf.sprintf "failed to submit plc operation: %d %s"
9898+ status msg ) ) )
9999+ else Lwt.return_ok ()
100100+ in
101101+ match plc_result with
102102+ | Error e ->
103103+ Lwt.return_error e
104104+ | Ok () ->
105105+ let () = Ttl_cache.String_cache.remove Id_resolver.Did.cache did in
106106+ let%lwt _ = Sequencer.sequence_identity db ~did ~handle () in
107107+ Lwt.return_ok () ) )
+2-2
pegasus/lib/lexicon_resolver.ml
···2424[@@deriving yojson {strict= false}]
25252626let cache : permission_set Ttl_cache.String_cache.t =
2727- Ttl_cache.String_cache.create (3 * Util.hour) ()
2727+ Ttl_cache.String_cache.create (3 * Util.Time.hour) ()
28282929(* reuse dns client from id_resolver *)
3030let dns_client = Id_resolver.Handle.dns_client
31313232(* resolve did authority for nsid *)
3333let resolve_did_authority nsid =
3434- let authority = Util.nsid_authority nsid in
3434+ let authority = Util.Syntax.nsid_authority nsid in
3535 try%lwt
3636 let%lwt result =
3737 Dns_client_lwt.getaddrinfo dns_client Dns.Rr_map.Txt
+5-5
pegasus/lib/migrations/migrations.ml
···6262 with _ -> None
63636464let run_migration db (id, name, sql) =
6565- Util.use_pool db (fun conn ->
6666- Util.transact conn (fun () ->
6565+ Util.Sqlite.use_pool db (fun conn ->
6666+ Util.Sqlite.transact conn (fun () ->
6767 let open Lwt_result.Infix in
6868 execute_raw conn sql
6969 >>= fun () ->
7070- let applied_at = Util.now_ms () in
7070+ let applied_at = Util.Time.now_ms () in
7171 Queries.record_migration ~id ~name ~applied_at conn ) )
72727373type migration_type = Data_store | User_store
···8080 | User_store ->
8181 User_store_migrations_sql.(read, file_list)
8282 in
8383- let%lwt () = Util.use_pool conn Queries.create_migrations_table in
8383+ let%lwt () = Util.Sqlite.use_pool conn Queries.create_migrations_table in
8484 let%lwt applied =
8585- Util.use_pool conn Queries.get_applied_migrations
8585+ Util.Sqlite.use_pool conn Queries.get_applied_migrations
8686 >|= List.map (fun m -> m.id)
8787 in
8888 let pending =
+1-1
pegasus/lib/oauth/client.ml
···11open Types
2233let fetch_client_metadata client_id : client_metadata Lwt.t =
44- let%lwt {status; _}, res = Util.http_get (Uri.of_string client_id) in
44+ let%lwt {status; _}, res = Util.Http.get (Uri.of_string client_id) in
55 if status <> `OK then
66 let%lwt () = Cohttp_lwt.Body.drain_body res in
77 failwith
+3-3
pegasus/lib/oauth/dpop.ml
···1515 Hashtbl.create Constants.jti_cache_size
16161717let cleanup_jti_cache () =
1818- let now = Util.now_ms () in
1818+ let now = Util.Time.now_ms () in
1919 Hashtbl.filter_map_inplace
2020 (fun _ expires_at -> if expires_at > now then Some expires_at else None)
2121 jti_cache
···5050 |> to_raw_string |> Jwt.b64_encode )
51515252let create_nonce_state secret =
5353- let counter = Util.now_ms () / Constants.dpop_rotation_interval_ms in
5353+ let counter = Util.Time.now_ms () / Constants.dpop_rotation_interval_ms in
5454 { secret
5555 ; counter
5656 ; prev= compute_nonce secret (pred counter)
···6060let nonce_state = ref (create_nonce_state Env.dpop_nonce_secret)
61616262let next_nonce () =
6363- let now_counter = Util.now_ms () / Constants.dpop_rotation_interval_ms in
6363+ let now_counter = Util.Time.now_ms () / Constants.dpop_rotation_interval_ms in
6464 let diff = now_counter - !nonce_state.counter in
6565 ( match diff with
6666 | 0 ->
···69697070(* check if permission_nsid is under include_nsid's authority *)
7171let is_parent_authority_of ~include_nsid ~permission_nsid =
7272- let include_authority = Util.nsid_authority include_nsid in
7373- let permission_authority = Util.nsid_authority permission_nsid in
7272+ let include_authority = Util.Syntax.nsid_authority include_nsid in
7373+ let permission_authority = Util.Syntax.nsid_authority permission_nsid in
7474 String.equal include_authority permission_authority
7575 || String.starts_with ~prefix:(include_authority ^ ".") permission_authority
7676
+13-13
pegasus/lib/passkey.ml
···126126127127let create_challenge ?did ~challenge_type db =
128128 let _challenge_obj, challenge_b64 = Webauthn.generate_challenge () in
129129- let now = Util.now_ms () in
129129+ let now = Util.Time.now_ms () in
130130 let expires_at = now + challenge_expiry_ms in
131131 let challenge_type_str =
132132 match challenge_type with
···136136 "authenticate"
137137 in
138138 let%lwt () =
139139- Util.use_pool db
139139+ Util.Sqlite.use_pool db
140140 @@ Queries.insert_challenge ~challenge:challenge_b64 ~did
141141 ~challenge_type:challenge_type_str ~expires_at ~created_at:now
142142 in
143143 Lwt.return challenge_b64
144144145145let verify_challenge ~challenge ~challenge_type db =
146146- let now = Util.now_ms () in
146146+ let now = Util.Time.now_ms () in
147147 let expected_type =
148148 match challenge_type with
149149 | `Register ->
···151151 | `Authenticate ->
152152 "authenticate"
153153 in
154154- match%lwt Util.use_pool db @@ Queries.get_challenge challenge now with
154154+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_challenge challenge now with
155155 | Some c when c.challenge_type = expected_type ->
156156 Lwt.return_some c
157157 | _ ->
158158 Lwt.return_none
159159160160let delete_challenge ~challenge db =
161161- Util.use_pool db @@ Queries.delete_challenge ~challenge
161161+ Util.Sqlite.use_pool db @@ Queries.delete_challenge ~challenge
162162163163let store_credential ~did ~credential_id ~public_key ~name db =
164164- let now = Util.now_ms () in
165165- Util.use_pool db
164164+ let now = Util.Time.now_ms () in
165165+ Util.Sqlite.use_pool db
166166 @@ Queries.insert_passkey ~did ~credential_id ~public_key ~sign_count:0 ~name
167167 ~created_at:now
168168169169let get_credentials_for_user ~did db =
170170- Util.use_pool db @@ Queries.get_passkeys_by_did ~did
170170+ Util.Sqlite.use_pool db @@ Queries.get_passkeys_by_did ~did
171171172172let get_credential_by_id ~credential_id db =
173173- Util.use_pool db @@ Queries.get_passkey_by_credential_id ~credential_id
173173+ Util.Sqlite.use_pool db @@ Queries.get_passkey_by_credential_id ~credential_id
174174175175let update_sign_count ~credential_id ~sign_count db =
176176- let now = Util.now_ms () in
177177- Util.use_pool db
176176+ let now = Util.Time.now_ms () in
177177+ Util.Sqlite.use_pool db
178178 @@ Queries.update_passkey_sign_count ~credential_id ~sign_count
179179 ~last_used_at:now
180180181181let delete_credential ~id ~did db =
182182- let%lwt () = Util.use_pool db @@ Queries.delete_passkey ~id ~did in
182182+ let%lwt () = Util.Sqlite.use_pool db @@ Queries.delete_passkey ~id ~did in
183183 Lwt.return_true
184184185185let rename_credential ~id ~did ~name db =
186186- let%lwt () = Util.use_pool db @@ Queries.rename_passkey ~id ~did ~name in
186186+ let%lwt () = Util.Sqlite.use_pool db @@ Queries.rename_passkey ~id ~did ~name in
187187 Lwt.return_true
188188189189let generate_registration_options ~did ~email ~existing_credentials db =
+2-2
pegasus/lib/plc.ml
···11open Cohttp
22open Cohttp_lwt
33open Cohttp_lwt_unix
44-open Util.Did_doc_types
44+open Util.Types
5566let default_endpoint = "https://plc.directory"
77···278278 did
279279 in
280280 let headers = Http.Header.init_with "Accept" "application/json" in
281281- let%lwt res, body = Util.http_get ~headers uri in
281281+ let%lwt res, body = Util.Http.get ~headers uri in
282282 match res.status with
283283 | `OK ->
284284 let%lwt body = Body.to_string body in
···182182183183let setup_security_key ~did ~name db =
184184 let secret = generate_secret () in
185185- let now = Util.now_ms () in
185185+ let now = Util.Time.now_ms () in
186186 let%lwt () =
187187- Util.use_pool db
187187+ Util.Sqlite.use_pool db
188188 @@ Queries.insert_security_key ~did ~name ~secret ~counter:0 ~created_at:now
189189 in
190190- let%lwt id = Util.use_pool db @@ Queries.get_last_insert_id () in
190190+ let%lwt id = Util.Sqlite.use_pool db @@ Queries.get_last_insert_id () in
191191 let issuer = "Pegasus PDS (" ^ Env.hostname ^ ")" in
192192 let uri = make_provisioning_uri ~secret ~account:did ~issuer in
193193 let secret_b32 =
···196196 Lwt.return (id, secret_b32, uri)
197197198198let verify_setup ~id ~did ~code db =
199199- match%lwt Util.use_pool db @@ Queries.get_security_key_by_id id did with
199199+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_security_key_by_id id did with
200200 | None ->
201201 Lwt.return_error "Security key not found"
202202 | Some sk -> (
···209209 | Error msg ->
210210 Lwt.return_error msg
211211 | Ok new_counter ->
212212- let now = Util.now_ms () in
212212+ let now = Util.Time.now_ms () in
213213 let%lwt () =
214214- Util.use_pool db
214214+ Util.Sqlite.use_pool db
215215 @@ Queries.verify_security_key ~id ~did ~verified_at:now
216216 ~counter:new_counter
217217 in
···219219220220let verify_login ~did ~code db =
221221 let%lwt keys =
222222- Util.use_pool db @@ Queries.get_verified_security_keys_by_did ~did
222222+ Util.Sqlite.use_pool db @@ Queries.get_verified_security_keys_by_did ~did
223223 in
224224 let rec try_keys = function
225225 | [] ->
···229229 | Error _ ->
230230 try_keys rest
231231 | Ok new_counter ->
232232- let now = Util.now_ms () in
232232+ let now = Util.Time.now_ms () in
233233 let%lwt () =
234234- Util.use_pool db
234234+ Util.Sqlite.use_pool db
235235 @@ Queries.update_counter_and_last_used ~id:sk.id
236236 ~counter:new_counter ~last_used_at:now
237237 in
···240240 try_keys keys
241241242242let resync_key ~id ~did ~code1 ~code2 db =
243243- match%lwt Util.use_pool db @@ Queries.get_security_key_by_id id did with
243243+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_security_key_by_id id did with
244244 | None ->
245245 Lwt.return_error "Security key not found"
246246 | Some sk -> (
···254254 Lwt.return_error msg
255255 | Ok new_counter ->
256256 let%lwt () =
257257- Util.use_pool db
257257+ Util.Sqlite.use_pool db
258258 @@ Queries.update_counter ~id:sk.id ~counter:new_counter
259259 in
260260 Lwt.return_ok () )
261261262262let get_keys_for_user ~did db =
263263- Util.use_pool db @@ Queries.get_security_keys_by_did ~did
263263+ Util.Sqlite.use_pool db @@ Queries.get_security_keys_by_did ~did
264264265265let delete_key ~id ~did db =
266266- let%lwt () = Util.use_pool db @@ Queries.delete_security_key ~id ~did in
266266+ let%lwt () = Util.Sqlite.use_pool db @@ Queries.delete_security_key ~id ~did in
267267 Lwt.return_true
268268269269let has_security_keys ~did db =
270270- match%lwt Util.use_pool db @@ Queries.has_security_keys ~did with
270270+ match%lwt Util.Sqlite.use_pool db @@ Queries.has_security_keys ~did with
271271 | Some _ ->
272272 Lwt.return_true
273273 | None ->
274274 Lwt.return_false
275275276276let count_security_keys ~did db =
277277- Util.use_pool db @@ Queries.count_security_keys ~did
277277+ Util.Sqlite.use_pool db @@ Queries.count_security_keys ~did
278278279279let count_verified_security_keys ~did db =
280280- Util.use_pool db @@ Queries.count_verified_security_keys ~did
280280+ Util.Sqlite.use_pool db @@ Queries.count_verified_security_keys ~did
+11-11
pegasus/lib/sequencer.ml
···444444 in
445445 match kind_result with
446446 | Ok kind ->
447447- Ok {seq= dbe.seq; time= Util.ms_to_iso8601 dbe.time; kind}
447447+ Ok {seq= dbe.seq; time= Util.Time.ms_to_iso8601 dbe.time; kind}
448448 | Error e ->
449449 Error ("failed to parse event: " ^ e) )
450450 | Error _ ->
···458458459459 let queue_max = 1000
460460461461- let notify_interval = 20 * Util.minute
461461+ let notify_interval = 20 * Util.Time.minute
462462463463 let ring : item array = Array.make ring_size {seq= 0; bytes= Bytes.empty}
464464···486486 head_seq := it.seq ;
487487 ring.(it.seq mod ring_size) <- it ;
488488 if !count < ring_size then incr count ;
489489- let now = Util.now_ms () in
489489+ let now = Util.Time.now_ms () in
490490 if now - !last_notified > notify_interval then begin
491491 last_notified := now ;
492492 List.iter
···726726let sequence_commit (conn : Data_store.t) ~(did : string) ~(commit : Cid.t)
727727 ~(rev : string) ?since ~(blocks : bytes) ~(ops : commit_evt_op list)
728728 ?(prev_data : Cid.t option) () : int Lwt.t =
729729- let time_ms = Util.now_ms () in
730730- let time_iso = Util.ms_to_iso8601 time_ms in
729729+ let time_ms = Util.Time.now_ms () in
730730+ let time_iso = Util.Time.ms_to_iso8601 time_ms in
731731 let evt : commit_evt =
732732 { rebase= false
733733 ; too_big= false
···748748749749let sequence_sync (conn : Data_store.t) ~(did : string) ~(rev : string)
750750 ~(blocks : bytes) () : int Lwt.t =
751751- let time_ms = Util.now_ms () in
752752- let time_iso = Util.ms_to_iso8601 time_ms in
751751+ let time_ms = Util.Time.now_ms () in
752752+ let time_iso = Util.Time.ms_to_iso8601 time_ms in
753753 let evt : sync_evt = {did; rev; blocks} in
754754 let raw = Dag_cbor.encode_yojson @@ Encode.format_sync evt in
755755 let%lwt seq = DB.append_event conn ~t:`Sync ~time:time_ms ~data:raw in
···759759760760let sequence_identity (conn : Data_store.t) ~(did : string)
761761 ?(handle : string option) () : int Lwt.t =
762762- let time_ms = Util.now_ms () in
763763- let time_iso = Util.ms_to_iso8601 time_ms in
762762+ let time_ms = Util.Time.now_ms () in
763763+ let time_iso = Util.Time.ms_to_iso8601 time_ms in
764764 let evt : identity_evt = {did; handle} in
765765 let raw = Dag_cbor.encode_yojson @@ Encode.format_identity evt in
766766 let%lwt seq = DB.append_event conn ~t:`Identity ~time:time_ms ~data:raw in
···770770771771let sequence_account (conn : Data_store.t) ~(did : string) ~(active : bool)
772772 ?(status : account_status option) () : int Lwt.t =
773773- let time_ms = Util.now_ms () in
774774- let time_iso = Util.ms_to_iso8601 time_ms in
773773+ let time_ms = Util.Time.now_ms () in
774774+ let time_iso = Util.Time.ms_to_iso8601 time_ms in
775775 let evt : account_evt = {did; active; status} in
776776 let raw = Dag_cbor.encode_yojson @@ Encode.format_account evt in
777777 let%lwt seq = DB.append_event conn ~t:`Account ~time:time_ms ~data:raw in
+1-1
pegasus/lib/session.ml
···198198 Lwt.return_some
199199 { actor with
200200 avatar_data_uri=
201201- Some (Util.make_data_uri ~mimetype ~data) }
201201+ Some (Util.Html.make_data_uri ~mimetype ~data) }
202202 | _ ->
203203 Lwt.return_some actor )
204204 | _ ->
+13-13
pegasus/lib/totp.ml
···9797 with _ -> false
98989999 let store_codes ~did ~codes db =
100100- let now = Util.now_ms () in
100100+ let now = Util.Time.now_ms () in
101101 Lwt_list.iter_s
102102 (fun code ->
103103 let code_hash = hash_code code in
104104- Util.use_pool db
104104+ Util.Sqlite.use_pool db
105105 @@ Queries.insert_backup_code ~did ~code_hash ~created_at:now )
106106 codes
107107108108 let regenerate ~did db =
109109- let%lwt () = Util.use_pool db @@ Queries.delete_backup_codes_by_did ~did in
109109+ let%lwt () = Util.Sqlite.use_pool db @@ Queries.delete_backup_codes_by_did ~did in
110110 let codes = generate_codes () in
111111 let%lwt () = store_codes ~did ~codes db in
112112 Lwt.return (List.map format_code codes)
···114114 let verify_and_consume ~did ~code db =
115115 let normalized_code = normalize_code code in
116116 let%lwt codes =
117117- Util.use_pool db @@ Queries.get_unused_backup_codes_by_did ~did
117117+ Util.Sqlite.use_pool db @@ Queries.get_unused_backup_codes_by_did ~did
118118 in
119119 let rec check = function
120120 | [] ->
121121 Lwt.return_false
122122 | c :: rest ->
123123 if verify_code_hash normalized_code c.code_hash then
124124- let now = Util.now_ms () in
124124+ let now = Util.Time.now_ms () in
125125 let%lwt () =
126126- Util.use_pool db
126126+ Util.Sqlite.use_pool db
127127 @@ Queries.mark_code_used ~id:c.id ~did ~used_at:now
128128 in
129129 Lwt.return_true
···132132 check codes
133133134134 let get_remaining_count ~did db =
135135- Util.use_pool db @@ Queries.count_unused_backup_codes ~did
135135+ Util.Sqlite.use_pool db @@ Queries.count_unused_backup_codes ~did
136136137137 let has_backup_codes ~did db =
138138 let%lwt count = get_remaining_count ~did db in
···244244 check 0
245245246246let create_secret ~did ~secret db =
247247- Util.use_pool db @@ Queries.set_totp_secret ~did ~secret
247247+ Util.Sqlite.use_pool db @@ Queries.set_totp_secret ~did ~secret
248248249249let get_secret ~did db =
250250- match%lwt Util.use_pool db @@ Queries.get_totp_secret ~did with
250250+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_totp_secret ~did with
251251 | Some (Some secret, verified_at) ->
252252 Lwt.return_some (secret, verified_at)
253253 | _ ->
···261261 Lwt.return_error "TOTP is already enabled"
262262 | Some (secret, None) ->
263263 if verify_code ~secret ~code then
264264- let now = Util.now_ms () in
264264+ let now = Util.Time.now_ms () in
265265 let%lwt () =
266266- Util.use_pool db @@ Queries.verify_totp_secret ~did ~verified_at:now
266266+ Util.Sqlite.use_pool db @@ Queries.verify_totp_secret ~did ~verified_at:now
267267 in
268268 Lwt.return_ok ()
269269 else Lwt.return_error "Invalid verification code"
270270271271-let disable ~did db = Util.use_pool db @@ Queries.clear_totp_secret ~did
271271+let disable ~did db = Util.Sqlite.use_pool db @@ Queries.clear_totp_secret ~did
272272273273let is_enabled ~did db =
274274- match%lwt Util.use_pool db @@ Queries.is_totp_enabled ~did with
274274+ match%lwt Util.Sqlite.use_pool db @@ Queries.is_totp_enabled ~did with
275275 | Some _ ->
276276 Lwt.return_true
277277 | None ->
+1-1
pegasus/lib/ttl_cache.ml
···10101111 let default_initial_capacity = 16
12121313- let[@inline] _now_ms () : time_ms = Util.now_ms ()
1313+ let[@inline] _now_ms () : time_ms = Util.Time.now_ms ()
14141515 let create ?capacity ?(initial_capacity = default_initial_capacity)
1616 default_ttl () : 'a t =
+16-16
pegasus/lib/two_factor.ml
···104104 Base64.(encode_string ~alphabet:uri_safe_alphabet ~pad:false token)
105105106106let is_2fa_enabled ~did db =
107107- match%lwt Util.use_pool db @@ Queries.is_2fa_enabled ~did with
107107+ match%lwt Util.Sqlite.use_pool db @@ Queries.is_2fa_enabled ~did with
108108 | Some 1 ->
109109 Lwt.return_true
110110 | _ ->
···113113let get_status ~did db =
114114 let%lwt totp_enabled = Totp.is_enabled ~did db in
115115 let%lwt email_2fa =
116116- match%lwt Util.use_pool db @@ Queries.get_email_2fa_enabled ~did with
116116+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_email_2fa_enabled ~did with
117117 | Some 1 ->
118118 Lwt.return_true
119119 | _ ->
···132132let get_available_methods ~did db =
133133 let%lwt totp_enabled = Totp.is_enabled ~did db in
134134 let%lwt email_2fa =
135135- match%lwt Util.use_pool db @@ Queries.get_email_2fa_enabled ~did with
135135+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_email_2fa_enabled ~did with
136136 | Some 1 ->
137137 Lwt.return_true
138138 | _ ->
···149149(* create a pending 2FA session after password verification *)
150150let create_pending_session ~did db =
151151 let session_token = generate_session_token () in
152152- let now = Util.now_ms () in
152152+ let now = Util.Time.now_ms () in
153153 let expires_at = now + pending_session_expiry_ms in
154154 let%lwt () =
155155- Util.use_pool db
155155+ Util.Sqlite.use_pool db
156156 @@ Queries.insert_pending_2fa ~session_token ~did ~password_verified_at:now
157157 ~expires_at ~created_at:now
158158 in
159159 Lwt.return session_token
160160161161let get_pending_session ~session_token db =
162162- let now = Util.now_ms () in
163163- Util.use_pool db @@ Queries.get_pending_2fa session_token now
162162+ let now = Util.Time.now_ms () in
163163+ Util.Sqlite.use_pool db @@ Queries.get_pending_2fa session_token now
164164165165let get_pending_session_for_did ~did db =
166166- let now = Util.now_ms () in
167167- Util.use_pool db @@ Queries.get_pending_2fa_for_did did now
166166+ let now = Util.Time.now_ms () in
167167+ Util.Sqlite.use_pool db @@ Queries.get_pending_2fa_for_did did now
168168169169let delete_pending_session ~session_token db =
170170- Util.use_pool db @@ Queries.delete_pending_2fa ~session_token
170170+ Util.Sqlite.use_pool db @@ Queries.delete_pending_2fa ~session_token
171171172172let send_email_code ~session_token ~actor db =
173173 let code = Util.make_code () in
174174- let now = Util.now_ms () in
174174+ let now = Util.Time.now_ms () in
175175 let expires_at = now + email_code_expiry_ms in
176176 let%lwt () =
177177- Util.use_pool db
177177+ Util.Sqlite.use_pool db
178178 @@ Queries.update_email_code ~session_token ~email_code:code
179179 ~email_code_expires_at:expires_at
180180 in
···189189let _verify_email_code ~code ~session =
190190 match (session.email_code, session.email_code_expires_at) with
191191 | Some stored_code, Some expires_at ->
192192- let now = Util.now_ms () in
192192+ let now = Util.Time.now_ms () in
193193 if now > expires_at then Lwt.return_error "Email code expired"
194194 else if stored_code = code then Lwt.return_ok session.did
195195 else Lwt.return_error "Invalid code"
···231231 else Lwt.return_error "Invalid backup code"
232232233233let enable_email_2fa ~did db =
234234- Util.use_pool db @@ Queries.set_email_2fa_enabled ~did ~enabled:1
234234+ Util.Sqlite.use_pool db @@ Queries.set_email_2fa_enabled ~did ~enabled:1
235235236236let disable_email_2fa ~did db =
237237- Util.use_pool db @@ Queries.set_email_2fa_enabled ~did ~enabled:0
237237+ Util.Sqlite.use_pool db @@ Queries.set_email_2fa_enabled ~did ~enabled:0
238238239239let is_email_2fa_enabled ~did db =
240240- match%lwt Util.use_pool db @@ Queries.get_email_2fa_enabled ~did with
240240+ match%lwt Util.Sqlite.use_pool db @@ Queries.get_email_2fa_enabled ~did with
241241 | Some 1 ->
242242 Lwt.return_true
243243 | _ ->
+40-40
pegasus/lib/user_store.ml
···457457 process_chunks chunks
458458end
459459460460-type t = {did: string; db: Util.caqti_pool}
460460+type t = {did: string; db: Util.Sqlite.caqti_pool}
461461462462let pool_cache : (string, t) Hashtbl.t = Hashtbl.create 64
463463···475475 Lwt.return cached
476476 | None ->
477477 let%lwt db =
478478- Util.connect_sqlite ?create ~write:true
478478+ Util.Sqlite.connect ?create ~write:true
479479 (Util.Constants.user_db_location did)
480480 in
481481 let%lwt () = Migrations.run_migrations User_store db in
···487487 if create = Some true then
488488 Util.mkfile_p (Util.Constants.user_db_filepath did) ~perm:0o644 ;
489489 let%lwt db =
490490- Util.connect_sqlite ?create ~write:false
490490+ Util.Sqlite.connect ?create ~write:false
491491 (Util.Constants.user_db_location did)
492492 in
493493 let%lwt () = Migrations.run_migrations User_store db in
···496496(* mst blocks; implements Writable_blockstore *)
497497498498let get_bytes t cid : Blob.t option Lwt.t =
499499- Util.use_pool t.db @@ Queries.get_block cid
499499+ Util.Sqlite.use_pool t.db @@ Queries.get_block cid
500500 >|= function Some {data; _} -> Some data | None -> None
501501502502let get_blocks t cids : Block_map.with_missing Lwt.t =
503503 if List.is_empty cids then
504504 Lwt.return ({blocks= Block_map.empty; missing= []} : Block_map.with_missing)
505505 else
506506- let%lwt blocks = Util.use_pool t.db @@ Queries.get_blocks cids in
506506+ let%lwt blocks = Util.Sqlite.use_pool t.db @@ Queries.get_blocks cids in
507507 let found_map =
508508 List.fold_left
509509 (fun acc ({cid; data} : block) -> Block_map.set cid data acc)
···521521 cids )
522522523523let has t cid : bool Lwt.t =
524524- Util.use_pool t.db @@ Queries.has_block cid
524524+ Util.Sqlite.use_pool t.db @@ Queries.has_block cid
525525 >|= function Some _ -> true | None -> false
526526527527let put_block t cid block : (bool, exn) Lwt_result.t =
528528 Lwt_result.catch
529529 @@ fun () ->
530530- match%lwt Util.use_pool t.db @@ Queries.put_block cid block with
530530+ match%lwt Util.Sqlite.use_pool t.db @@ Queries.put_block cid block with
531531 | Some _ ->
532532 Lwt.return true
533533 | None ->
···539539 else
540540 Lwt_result.catch (fun () ->
541541 let%lwt () =
542542- Util.use_pool t.db (fun conn -> Bulk.put_blocks entries conn)
542542+ Util.Sqlite.use_pool t.db (fun conn -> Bulk.put_blocks entries conn)
543543 in
544544 Lwt.return (List.length entries) )
545545546546let delete_block t cid : (bool, exn) Lwt_result.t =
547547 Lwt_result.catch
548548- @@ fun () -> Util.use_pool t.db @@ Queries.delete_block cid >|= fun _ -> true
548548+ @@ fun () -> Util.Sqlite.use_pool t.db @@ Queries.delete_block cid >|= fun _ -> true
549549550550let delete_many t cids : (int, exn) Lwt_result.t =
551551 Lwt_result.catch
552552- @@ fun () -> Util.use_pool t.db @@ Queries.delete_blocks cids >|= List.length
552552+ @@ fun () -> Util.Sqlite.use_pool t.db @@ Queries.delete_blocks cids >|= List.length
553553554554let clear_mst t : unit Lwt.t =
555555- let%lwt () = Util.use_pool t.db Queries.clear_mst in
555555+ let%lwt () = Util.Sqlite.use_pool t.db Queries.clear_mst in
556556 Lwt.return_unit
557557558558(* mst misc *)
559559560560-let count_blocks t : int Lwt.t = Util.use_pool t.db @@ Queries.count_blocks ()
560560+let count_blocks t : int Lwt.t = Util.Sqlite.use_pool t.db @@ Queries.count_blocks ()
561561562562(* repo commit *)
563563564564let get_commit t : (Cid.t * signed_commit) option Lwt.t =
565565- let%lwt commit = Util.use_pool t.db Queries.get_commit in
565565+ let%lwt commit = Util.Sqlite.use_pool t.db Queries.get_commit in
566566 Lwt.return
567567 @@ Option.map
568568 (fun (cid, data) ->
···575575 let data = commit |> signed_commit_to_yojson |> Dag_cbor.encode_yojson in
576576 let cid = Cid.create Dcbor data in
577577 ( Lwt_result.catch
578578- @@ fun () -> Util.use_pool t.db @@ Queries.put_commit cid data )
578578+ @@ fun () -> Util.Sqlite.use_pool t.db @@ Queries.put_commit cid data )
579579 |> Lwt_result.map (fun () -> cid)
580580581581(* records *)
582582583583let get_record t path : record option Lwt.t =
584584- Util.use_pool t.db @@ Queries.get_record ~path
584584+ Util.Sqlite.use_pool t.db @@ Queries.get_record ~path
585585 >|= Option.map (fun (cid, data, since) ->
586586 {path; cid; value= Lex.of_cbor data; since} )
587587588588let get_record_cid t path : Cid.t option Lwt.t =
589589- Util.use_pool t.db @@ Queries.get_record_cid ~path
589589+ Util.Sqlite.use_pool t.db @@ Queries.get_record_cid ~path
590590591591let get_all_record_cids t : (string * Cid.t) list Lwt.t =
592592- Util.use_pool t.db Queries.get_all_record_cids
592592+ Util.Sqlite.use_pool t.db Queries.get_all_record_cids
593593594594let get_records_by_cids t cids : (Cid.t * Blob.t) list Lwt.t =
595595 if List.is_empty cids then Lwt.return []
596596 else
597597- Util.use_pool t.db @@ Queries.get_records_by_cids cids
597597+ Util.Sqlite.use_pool t.db @@ Queries.get_records_by_cids cids
598598 >|= List.map (fun ({cid; data} : block) -> (cid, data))
599599600600let list_records t ?(limit = 100) ?(cursor = "") ?(reverse = false) collection :
···602602 let fn =
603603 if reverse then Queries.list_records_reverse else Queries.list_records
604604 in
605605- Util.use_pool t.db @@ fn ~collection ~limit ~cursor
605605+ Util.Sqlite.use_pool t.db @@ fn ~collection ~limit ~cursor
606606 >|= List.map (fun (path, cid, data, since) ->
607607 {path; cid; value= Lex.of_cbor data; since} )
608608609609-let count_records t : int Lwt.t = Util.use_pool t.db @@ Queries.count_records ()
609609+let count_records t : int Lwt.t = Util.Sqlite.use_pool t.db @@ Queries.count_records ()
610610611611let list_collections t : string list Lwt.t =
612612- Util.use_pool t.db @@ Queries.list_collections
612612+ Util.Sqlite.use_pool t.db @@ Queries.list_collections
613613614614let put_record t record path : (Cid.t * bytes) Lwt.t =
615615 let cid, data = Lex.to_cbor_block record in
616616 let since = Tid.now () in
617617 let%lwt () =
618618- Util.use_pool t.db @@ Queries.put_record ~path ~cid ~data ~since
618618+ Util.Sqlite.use_pool t.db @@ Queries.put_record ~path ~cid ~data ~since
619619 in
620620 Lwt.return (cid, data)
621621622622let put_record_raw t ~path ~cid ~data ~since : unit Lwt.t =
623623- Util.use_pool t.db @@ Queries.put_record ~path ~cid ~data ~since
623623+ Util.Sqlite.use_pool t.db @@ Queries.put_record ~path ~cid ~data ~since
624624625625let delete_record t path : unit Lwt.t =
626626- Util.use_pool t.db (fun conn ->
627627- Util.transact conn (fun () ->
626626+ Util.Sqlite.use_pool t.db (fun conn ->
627627+ Util.Sqlite.transact conn (fun () ->
628628 let del = Queries.delete_record path conn in
629629 let$! () = del in
630630 let$! deleted_blobs =
···642642(* blobs *)
643643644644let get_blob t cid : blob_with_contents option Lwt.t =
645645- match%lwt Util.use_pool t.db @@ Queries.get_blob ~cid with
645645+ match%lwt Util.Sqlite.use_pool t.db @@ Queries.get_blob ~cid with
646646 | None ->
647647 Lwt.return_none
648648 | Some (cid, mimetype, storage_str) -> (
···655655 Lwt.return_none )
656656657657let get_blob_metadata t cid : blob option Lwt.t =
658658- match%lwt Util.use_pool t.db @@ Queries.get_blob ~cid with
658658+ match%lwt Util.Sqlite.use_pool t.db @@ Queries.get_blob ~cid with
659659 | None ->
660660 Lwt.return_none
661661 | Some (cid, mimetype, storage_str) ->
···663663 Lwt.return_some {cid; mimetype; storage}
664664665665let list_blobs ?since t ~limit ~cursor : Cid.t list Lwt.t =
666666- Util.use_pool t.db
666666+ Util.Sqlite.use_pool t.db
667667 @@
668668 match since with
669669 | Some since ->
···673673674674let list_missing_blobs ?(limit = 500) ?(cursor = "") t :
675675 (string * Cid.t) list Lwt.t =
676676- Util.use_pool t.db @@ Queries.list_missing_blobs ~limit ~cursor
676676+ Util.Sqlite.use_pool t.db @@ Queries.list_missing_blobs ~limit ~cursor
677677678678-let count_blobs t : int Lwt.t = Util.use_pool t.db @@ Queries.count_blobs ()
678678+let count_blobs t : int Lwt.t = Util.Sqlite.use_pool t.db @@ Queries.count_blobs ()
679679680680let count_referenced_blobs t : int Lwt.t =
681681- Util.use_pool t.db @@ Queries.count_referenced_blobs ()
681681+ Util.Sqlite.use_pool t.db @@ Queries.count_referenced_blobs ()
682682683683let put_blob t cid mimetype data : Cid.t Lwt.t =
684684 let%lwt storage = Blob_store.put ~did:t.did ~cid ~data in
685685 let storage_str = Blob_store.storage_to_string storage in
686686- Util.use_pool t.db @@ Queries.put_blob cid mimetype storage_str
686686+ Util.Sqlite.use_pool t.db @@ Queries.put_blob cid mimetype storage_str
687687688688let delete_blob t cid : unit Lwt.t =
689689 let%lwt blob_opt = get_blob_metadata t cid in
···692692 delete_blob_file ~did:t.did ~cid ~storage
693693 | None ->
694694 () ) ;
695695- Util.use_pool t.db @@ Queries.delete_blob cid
695695+ Util.Sqlite.use_pool t.db @@ Queries.delete_blob cid
696696697697let delete_orphaned_blobs_by_record_path t path :
698698 (Cid.t * Blob_store.storage) list Lwt.t =
699699 let%lwt results =
700700- Util.use_pool t.db @@ Queries.delete_orphaned_blobs_by_record_path path
700700+ Util.Sqlite.use_pool t.db @@ Queries.delete_orphaned_blobs_by_record_path path
701701 in
702702 Lwt.return
703703 @@ List.map
···706706 results
707707708708let list_blob_refs t path : Cid.t list Lwt.t =
709709- Util.use_pool t.db @@ Queries.list_blob_refs path
709709+ Util.Sqlite.use_pool t.db @@ Queries.list_blob_refs path
710710711711let put_blob_ref t path cid : unit Lwt.t =
712712- Util.use_pool t.db @@ Queries.put_blob_ref path cid
712712+ Util.Sqlite.use_pool t.db @@ Queries.put_blob_ref path cid
713713714714let put_blob_refs t path cids : (unit, exn) Lwt_result.t =
715715 if List.is_empty cids then Lwt.return_ok ()
716716 else
717717 Lwt_result.map (fun _ -> ())
718718- @@ Util.multi_query t.db
718718+ @@ Util.Sqlite.multi_query t.db
719719 (List.map (fun cid -> Queries.put_blob_ref cid path) cids)
720720721721let clear_blob_refs t path cids : unit Lwt.t =
722722 if List.is_empty cids then Lwt.return_unit
723723- else Util.use_pool t.db @@ Queries.clear_blob_refs path cids
723723+ else Util.Sqlite.use_pool t.db @@ Queries.clear_blob_refs path cids
724724725725let update_blob_storage t cid storage : unit Lwt.t =
726726 let storage_str = Blob_store.storage_to_string storage in
727727- Util.use_pool t.db @@ Queries.update_blob_storage cid storage_str
727727+ Util.Sqlite.use_pool t.db @@ Queries.update_blob_storage cid storage_str
728728729729let list_blobs_by_storage t ~storage ~limit ~cursor :
730730 (Cid.t * string) list Lwt.t =
731731 let storage_str = Blob_store.storage_to_string storage in
732732- Util.use_pool t.db
732732+ Util.Sqlite.use_pool t.db
733733 @@ Queries.list_blobs_by_storage ~storage:storage_str ~limit ~cursor
-600
pegasus/lib/util.ml
···11-module Constants = struct
22- let data_dir =
33- Core.Filename.to_absolute_exn Env.data_dir
44- ~relative_to:(Core_unix.getcwd ())
55-66- let pegasus_db_filepath = Filename.concat data_dir "pegasus.db"
77-88- let pegasus_db_location = "sqlite3://" ^ pegasus_db_filepath |> Uri.of_string
99-1010- let user_db_filepath did =
1111- let dirname = Filename.concat data_dir "store" in
1212- let filename = Str.global_replace (Str.regexp ":") "_" did in
1313- Filename.concat dirname filename ^ ".db"
1414-1515- let user_db_location did =
1616- "sqlite3://" ^ user_db_filepath did |> Uri.of_string
1717-1818- let user_blobs_location did =
1919- did
2020- |> Str.global_replace (Str.regexp ":") "_"
2121- |> (Filename.concat data_dir "blobs" |> Filename.concat)
2222-end
2323-2424-module Syntax = struct
2525- let unwrap m =
2626- match%lwt m with
2727- | Ok x ->
2828- Lwt.return x
2929- | Error e ->
3030- raise (Caqti_error.Exn e)
3131-3232- (* unwraps an Lwt result, raising an exception if there's an error *)
3333- let ( let$! ) m f =
3434- match%lwt m with Ok x -> f x | Error e -> raise (Caqti_error.Exn e)
3535-3636- (* unwraps an Lwt result, raising an exception if there's an error *)
3737- let ( >$! ) m f =
3838- match%lwt m with
3939- | Ok x ->
4040- Lwt.return (f x)
4141- | Error e ->
4242- raise (Caqti_error.Exn e)
4343-end
4444-4545-module Rapper = struct
4646- module CID : Rapper.CUSTOM with type t = Cid.t = struct
4747- type t = Cid.t
4848-4949- let t =
5050- let encode cid =
5151- try Ok (Cid.to_string cid) with e -> Error (Printexc.to_string e)
5252- in
5353- Caqti_type.(custom ~encode ~decode:Cid.of_string string)
5454- end
5555-5656- module Blob : Rapper.CUSTOM with type t = bytes = struct
5757- type t = bytes
5858-5959- let t =
6060- let encode blob =
6161- try Ok (Bytes.to_string blob) with e -> Error (Printexc.to_string e)
6262- in
6363- let decode blob =
6464- try Ok (Bytes.of_string blob) with e -> Error (Printexc.to_string e)
6565- in
6666- Caqti_type.(custom ~encode ~decode string)
6767- end
6868-6969- module Json : Rapper.CUSTOM with type t = Yojson.Safe.t = struct
7070- type t = Yojson.Safe.t
7171-7272- let t =
7373- let encode json =
7474- try Ok (Yojson.Safe.to_string json ~std:true)
7575- with e -> Error (Printexc.to_string e)
7676- in
7777- let decode json =
7878- try Ok (Yojson.Safe.from_string json)
7979- with e -> Error (Printexc.to_string e)
8080- in
8181- Caqti_type.(custom ~encode ~decode string)
8282- end
8383-end
8484-8585-module Did_doc_types = struct
8686- type string_or_null = string option
8787-8888- let string_or_null_to_yojson = function Some s -> `String s | None -> `Null
8989-9090- let string_or_null_of_yojson = function
9191- | `String s ->
9292- Ok (Some s)
9393- | `Null ->
9494- Ok None
9595- | _ ->
9696- Error "invalid field value"
9797-9898- type string_or_strings = [`String of string | `Strings of string list]
9999-100100- let string_or_strings_to_yojson = function
101101- | `String c ->
102102- `String c
103103- | `Strings cs ->
104104- `List (List.map (fun c -> `String c) cs)
105105-106106- let string_or_strings_of_yojson = function
107107- | `String c ->
108108- Ok (`Strings [c])
109109- | `List cs ->
110110- Ok (`Strings (Yojson.Safe.Util.filter_string cs))
111111- | _ ->
112112- Error "invalid field value"
113113-114114- type string_map = (string * string) list
115115-116116- let string_map_to_yojson = function
117117- | [] ->
118118- `Assoc []
119119- | m ->
120120- `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
121121-122122- let string_map_of_yojson = function
123123- | `Null ->
124124- Ok []
125125- | `Assoc m ->
126126- Ok
127127- (List.filter_map
128128- (fun (k, v) ->
129129- match (k, v) with _, `String s -> Some (k, s) | _, _ -> None )
130130- m )
131131- | _ ->
132132- Error "invalid field value"
133133-134134- type string_or_string_map = [`String of string | `String_map of string_map]
135135-136136- let string_or_string_map_to_yojson = function
137137- | `String c ->
138138- `String c
139139- | `String_map m ->
140140- `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
141141-142142- let string_or_string_map_of_yojson = function
143143- | `String c ->
144144- Ok (`String c)
145145- | `Assoc m ->
146146- string_map_of_yojson (`Assoc m) |> Result.map (fun m -> `String_map m)
147147- | _ ->
148148- Error "invalid field value"
149149-150150- type string_or_string_map_or_either_list =
151151- [ `String of string
152152- | `String_map of string_map
153153- | `List of string_or_string_map list ]
154154-155155- let string_or_string_map_or_either_list_to_yojson = function
156156- | `String c ->
157157- `String c
158158- | `String_map m ->
159159- `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
160160- | `List l ->
161161- `List (List.map string_or_string_map_to_yojson l)
162162-163163- let string_or_string_map_or_either_list_of_yojson = function
164164- | `String c ->
165165- Ok (`String c)
166166- | `Assoc m ->
167167- string_map_of_yojson (`Assoc m) |> Result.map (fun m -> `String_map m)
168168- | `List l ->
169169- Ok
170170- (`List
171171- ( List.map string_or_string_map_of_yojson l
172172- |> List.filter_map (function Ok x -> Some x | Error _ -> None) ) )
173173- | _ ->
174174- Error "invalid field value"
175175-end
176176-177177-type caqti_pool = (Caqti_lwt.connection, Caqti_error.t) Caqti_lwt_unix.Pool.t
178178-179179-(* turns a caqti error into an exception *)
180180-let caqti_result_exn = function
181181- | Ok x ->
182182- Ok x
183183- | Error caqti_err ->
184184- Error (Caqti_error.Exn caqti_err)
185185-186186-let _init_connection (module Db : Rapper_helper.CONNECTION) :
187187- (unit, Caqti_error.t) Lwt_result.t =
188188- let open Lwt_result.Syntax in
189189- let open Caqti_request.Infix in
190190- let open Caqti_type in
191191- let* _ =
192192- Db.find (((unit ->! string) ~oneshot:true) "PRAGMA journal_mode=WAL") ()
193193- in
194194- let* _ =
195195- Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA foreign_keys=ON") ()
196196- in
197197- let* _ =
198198- Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA synchronous=NORMAL") ()
199199- in
200200- let* _ =
201201- Db.find (((unit ->! int) ~oneshot:true) "PRAGMA busy_timeout=5000") ()
202202- in
203203- Lwt.return_ok ()
204204-205205-(* creates an sqlite pool *)
206206-let connect_sqlite ?(create = false) ?(write = true) db_uri : caqti_pool Lwt.t =
207207- let uri =
208208- Uri.add_query_params' db_uri
209209- [("create", string_of_bool create); ("write", string_of_bool write)]
210210- in
211211- let pool_config = Caqti_pool_config.create ~max_size:16 ~max_idle_size:4 () in
212212- match
213213- Caqti_lwt_unix.connect_pool ~pool_config ~post_connect:_init_connection uri
214214- with
215215- | Ok pool ->
216216- Lwt.return pool
217217- | Error e ->
218218- raise (Caqti_error.Exn e)
219219-220220-let with_connection db_uri f =
221221- match%lwt
222222- Caqti_lwt_unix.with_connection db_uri (fun conn ->
223223- match%lwt _init_connection conn with
224224- | Ok () ->
225225- f conn
226226- | Error e ->
227227- Lwt.return_error e )
228228- with
229229- | Ok result ->
230230- Lwt.return result
231231- | Error e ->
232232- raise (Caqti_error.Exn e)
233233-234234-let use_pool ?(timeout = 60.0) pool
235235- (f : Caqti_lwt.connection -> ('a, Caqti_error.t) Lwt_result.t) : 'a Lwt.t =
236236- match%lwt
237237- Lwt_unix.with_timeout timeout (fun () -> Caqti_lwt_unix.Pool.use f pool)
238238- with
239239- | Ok res ->
240240- Lwt.return res
241241- | Error e ->
242242- raise (Caqti_error.Exn e)
243243-244244-let transact conn fn : (unit, 'e) Lwt_result.t =
245245- let module C = (val conn : Caqti_lwt.CONNECTION) in
246246- match%lwt C.start () with
247247- | Ok () -> (
248248- try%lwt
249249- match%lwt fn () with
250250- | Ok _ -> (
251251- match%lwt C.commit () with
252252- | Ok () ->
253253- Lwt.return_ok ()
254254- | Error e -> (
255255- match%lwt C.rollback () with
256256- | Ok () ->
257257- Lwt.return_error e
258258- | Error e ->
259259- Lwt.return_error e ) )
260260- | Error e -> (
261261- match%lwt C.rollback () with
262262- | Ok () ->
263263- Lwt.return_error e
264264- | Error e ->
265265- Lwt.return_error e )
266266- with e -> (
267267- match%lwt C.rollback () with
268268- | Ok () ->
269269- Lwt.return_error
270270- ( match e with
271271- | Caqti_error.Exn e ->
272272- e
273273- | e ->
274274- Caqti_error.request_failed ~query:"unknown"
275275- ~uri:(Uri.of_string "//unknown")
276276- (Caqti_error.Msg (Printexc.to_string e)) )
277277- | Error e ->
278278- Lwt.return_error e ) )
279279- | Error e ->
280280- Lwt.return_error e
281281-282282-(* runs a bunch of queries in a transaction, catches duplicate insertion, returning how many succeeded *)
283283-let multi_query pool
284284- (queries : (Caqti_lwt.connection -> ('a, Caqti_error.t) Lwt_result.t) list)
285285- : (int, exn) Lwt_result.t =
286286- let open Syntax in
287287- Lwt_result.catch (fun () ->
288288- use_pool pool (fun connection ->
289289- let module C = (val connection : Caqti_lwt.CONNECTION) in
290290- let$! () = C.start () in
291291- let is_ignorable_error e =
292292- match (e : Caqti_error.t) with
293293- | `Request_failed qe | `Response_failed qe -> (
294294- match Caqti_error.cause (`Request_failed qe) with
295295- | `Not_null_violation | `Unique_violation ->
296296- true
297297- | _ ->
298298- false )
299299- | _ ->
300300- false
301301- in
302302- let rec aux acc queries =
303303- match acc with
304304- | Error e ->
305305- Lwt.return_error e
306306- | Ok count -> (
307307- match queries with
308308- | [] ->
309309- Lwt.return (Ok count)
310310- | query :: rest -> (
311311- let%lwt result = query connection in
312312- match result with
313313- | Ok _ ->
314314- aux (Ok (count + 1)) rest
315315- | Error e ->
316316- if is_ignorable_error e then aux (Ok count) rest
317317- else Lwt.return_error e ) )
318318- in
319319- let%lwt result = aux (Ok 0) queries in
320320- match result with
321321- | Ok count ->
322322- let$! () = C.commit () in
323323- Lwt.return_ok count
324324- | Error e ->
325325- let%lwt _ = C.rollback () in
326326- Lwt.return_error e ) )
327327-328328-let minute = 60 * 1000
329329-330330-let hour = 60 * minute
331331-332332-let day = 24 * hour
333333-334334-(* unix timestamp *)
335335-let now_ms () : int = int_of_float (Unix.gettimeofday () *. 1000.)
336336-337337-let ms_to_iso8601 ms =
338338- let s = float_of_int ms /. 1000. in
339339- Timedesc.(of_timestamp_float_s_exn s |> to_iso8601)
340340-341341-(* returns all blob refs in a record *)
342342-let rec find_blob_refs (record : Mist.Lex.repo_record) : Mist.Blob_ref.t list =
343343- let rec aux acc entries =
344344- List.fold_left
345345- (fun acc value ->
346346- match value with
347347- | `BlobRef blob ->
348348- blob :: acc
349349- | `LexMap map ->
350350- find_blob_refs map @ acc
351351- | `LexArray arr ->
352352- aux acc (Array.to_list arr) @ acc
353353- | _ ->
354354- acc )
355355- acc entries
356356- in
357357- aux [] (Mist.Lex.String_map.bindings record |> List.map snd)
358358- |> List.sort_uniq (fun (r1 : Mist.Blob_ref.t) r2 -> Cid.compare r1.ref r2.ref)
359359-360360-type validate_handle_error =
361361- | InvalidFormat of string
362362- | TooShort of string
363363- | TooLong of string
364364-365365-let validate_handle handle =
366366- (* if it's a custom domain, just check that it contains a period *)
367367- if not (String.ends_with ~suffix:("." ^ Env.hostname) handle) then
368368- if not (String.contains handle '.') then
369369- Error (InvalidFormat ("must end with " ^ "." ^ Env.hostname))
370370- else Ok ()
371371- else
372372- let front =
373373- String.sub handle 0
374374- (String.length handle - (String.length Env.hostname + 1))
375375- in
376376- if String.contains front '.' then
377377- Error (InvalidFormat "can't contain periods")
378378- else
379379- match String.length front with
380380- | l when l < 3 ->
381381- Error (TooShort "must be at least 3 characters")
382382- | l when l > 18 ->
383383- Error (TooLong "must be at most 18 characters")
384384- | _ ->
385385- Ok ()
386386-387387-let mkfile_p path ~perm =
388388- Core_unix.mkdir_p (Filename.dirname path) ~perm:0o755 ;
389389- Core_unix.openfile ~mode:[O_CREAT; O_WRONLY] ~perm path |> Core_unix.close
390390-391391-let sig_matches_some_did_key ~did_keys ~signature ~msg =
392392- List.find_opt
393393- (fun key ->
394394- let raw, (module Curve) =
395395- Kleidos.parse_multikey_str (String.sub key 8 (String.length key - 8))
396396- in
397397- let valid =
398398- Curve.verify ~pubkey:(Curve.normalize_pubkey_to_raw raw) ~signature ~msg
399399- in
400400- valid )
401401- did_keys
402402- <> None
403403-404404-let request_ip req =
405405- Dream.header req "X-Forwarded-For"
406406- |> Option.value ~default:(Dream.client req)
407407- |> String.split_on_char ',' |> List.hd |> String.split_on_char ':' |> List.hd
408408- |> String.trim
409409-410410-let rec http_get ?(max_redirects = 5) ?(no_drain = false) ?headers uri =
411411- let ua = "pegasus (" ^ Env.host_endpoint ^ ")" in
412412- let headers =
413413- match headers with
414414- | Some headers ->
415415- Http.Header.add_unless_exists headers "User-Agent" ua
416416- | None ->
417417- Http.Header.of_list [("User-Agent", ua)]
418418- in
419419- let%lwt ans = Cohttp_lwt_unix.Client.get ~headers uri in
420420- follow_redirect ~max_redirects ~no_drain uri ans
421421-422422-and follow_redirect ~max_redirects ~no_drain request_uri (response, body) =
423423- let status = Http.Response.status response in
424424- (* the unconsumed body would otherwise leak memory *)
425425- let%lwt () =
426426- if status <> `OK && not no_drain then Cohttp_lwt.Body.drain_body body
427427- else Lwt.return_unit
428428- in
429429- match status with
430430- | `Permanent_redirect | `Moved_permanently ->
431431- handle_redirect ~permanent:true ~max_redirects request_uri response
432432- | `Found | `Temporary_redirect ->
433433- handle_redirect ~permanent:false ~max_redirects request_uri response
434434- | _ ->
435435- Lwt.return (response, body)
436436-437437-and handle_redirect ~permanent ~max_redirects request_uri response =
438438- if max_redirects <= 0 then failwith "too many redirects"
439439- else
440440- let headers = Http.Response.headers response in
441441- let location = Http.Header.get headers "location" in
442442- match location with
443443- | None ->
444444- failwith "redirection without Location header"
445445- | Some url ->
446446- let uri = Uri.of_string url in
447447- let%lwt () =
448448- if permanent then
449449- Logs_lwt.warn (fun m ->
450450- m "Permanent redirection from %s to %s"
451451- (Uri.to_string request_uri)
452452- url )
453453- else Lwt.return_unit
454454- in
455455- http_get uri ~max_redirects:(max_redirects - 1)
456456-457457-let copy_query req = Dream.all_queries req |> List.map (fun (k, v) -> (k, [v]))
458458-459459-let make_headers headers =
460460- List.fold_left
461461- (fun headers (k, v) ->
462462- match v with
463463- | Some value ->
464464- Http.Header.add headers k value
465465- | None ->
466466- headers )
467467- (Http.Header.init ()) headers
468468-469469-let str_contains ~affix str =
470470- let re = Str.regexp_string affix in
471471- try
472472- ignore (Str.search_forward re str 0) ;
473473- true
474474- with Not_found -> false
475475-476476-let make_code () =
477477- let () = Mirage_crypto_rng_unix.use_default () in
478478- let token =
479479- Multibase.Base32.encode_string ~pad:false
480480- @@ Mirage_crypto_rng_unix.getrandom 8
481481- in
482482- String.sub token 0 5 ^ "-" ^ String.sub token 5 5
483483-484484-module type Template = sig
485485- type props
486486-487487- val props_of_json : Yojson.Basic.t -> props
488488-489489- val props_to_json : props -> Yojson.Basic.t
490490-491491- val make : ?key:string -> props:props -> unit -> React.element
492492-end
493493-494494-let render_html ?status ?title (type props)
495495- (template : (module Template with type props = props)) ~props =
496496- let module Template = (val template : Template with type props = props) in
497497- let props_json = Template.props_to_json props |> Yojson.Basic.to_string in
498498- let page_data = Printf.sprintf "window.__PAGE__ = {props: %s};" props_json in
499499- let app = Template.make ~props () in
500500- let page =
501501- Frontend.Layout.make ?title ~favicon:Env.favicon_url ~children:app ()
502502- in
503503- Dream.stream ?status
504504- ~headers:[("Content-Type", "text/html")]
505505- (fun stream ->
506506- [%lwt
507507- let html, subscribe =
508508- ReactServerDOM.render_html ~skipRoot:false
509509- ~bootstrapScriptContent:page_data
510510- ~bootstrapScripts:["/public/client.js"] page
511511- in
512512- [%lwt
513513- let () = Dream.write stream html in
514514- [%lwt
515515- let () = Dream.flush stream in
516516- [%lwt
517517- let () =
518518- subscribe (fun chunk ->
519519- [%lwt
520520- let () = Dream.write stream chunk in
521521- Dream.flush stream] )
522522- in
523523- Dream.flush stream]]]] )
524524-525525-let make_data_uri ~mimetype ~data =
526526- let base64_data = data |> Bytes.to_string |> Base64.encode_string in
527527- Printf.sprintf "data:%s;base64,%s" mimetype base64_data
528528-529529-let at_uri_regexp =
530530- Re.Pcre.re
531531- {|^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]\/\\]*))?$|}
532532- |> Re.compile
533533-534534-type at_uri =
535535- {repo: string; collection: string; rkey: string; fragment: string option}
536536-537537-let parse_at_uri uri =
538538- match Re.exec_opt at_uri_regexp uri with
539539- | None ->
540540- None
541541- | Some m -> (
542542- try
543543- Some
544544- { repo= Re.Group.get m 1
545545- ; collection= Re.Group.get m 2
546546- ; rkey= Re.Group.get m 3
547547- ; fragment= Re.Group.get_opt m 4 }
548548- with _ -> None )
549549-550550-let make_at_uri ~repo ~collection ~rkey ~fragment =
551551- Printf.sprintf "at://%s/%s/%s%s" repo collection rkey
552552- (Option.value ~default:"" fragment)
553553-554554-let nsid_authority nsid =
555555- match String.rindex_opt nsid '.' with
556556- | None ->
557557- nsid
558558- | Some idx ->
559559- String.sub nsid 0 idx
560560-561561-let send_email_or_log ~(recipients : Letters.recipient list) ~subject
562562- ~(body : Letters.body) =
563563- let log_email () =
564564- match body with
565565- | Plain text | Html text | Mixed (text, _, _) ->
566566- let to_addr =
567567- List.find_map
568568- (fun (r : Letters.recipient) ->
569569- match r with To addr -> Some addr | _ -> None )
570570- recipients
571571- |> Option.get
572572- in
573573- Log.info (fun log -> log "email to %s: %s" to_addr text)
574574- in
575575- match (Env.smtp_config, Env.smtp_sender) with
576576- | Some config, Some sender -> (
577577- match Letters.create_email ~from:sender ~recipients ~subject ~body () with
578578- | Error e ->
579579- failwith (Printf.sprintf "failed to construct email: %s" e)
580580- | Ok message -> (
581581- try%lwt Letters.send ~config ~sender ~recipients ~message
582582- with e ->
583583- Log.log_exn e ;
584584- Lwt.return (log_email ()) ) )
585585- | _ ->
586586- Lwt.return (log_email ())
587587-588588-let s3_error_to_string : Aws_s3_lwt.S3.error -> string = function
589589- | Redirect endpoint ->
590590- "redirect to " ^ endpoint.host
591591- | Throttled ->
592592- "throttled"
593593- | Unknown (code, msg) ->
594594- Printf.sprintf "unknown error %d: %s" code msg
595595- | Failed exn ->
596596- Printf.sprintf "failed: %s" (Printexc.to_string exn)
597597- | Forbidden ->
598598- "forbidden"
599599- | Not_found ->
600600- "not found"
+20
pegasus/lib/util/constants.ml
···11+ let data_dir =
22+ Core.Filename.to_absolute_exn Env.data_dir
33+ ~relative_to:(Core_unix.getcwd ())
44+55+ let pegasus_db_filepath = Filename.concat data_dir "pegasus.db"
66+77+ let pegasus_db_location = "sqlite3://" ^ pegasus_db_filepath |> Uri.of_string
88+99+ let user_db_filepath did =
1010+ let dirname = Filename.concat data_dir "store" in
1111+ let filename = Str.global_replace (Str.regexp ":") "_" did in
1212+ Filename.concat dirname filename ^ ".db"
1313+1414+ let user_db_location did =
1515+ "sqlite3://" ^ user_db_filepath did |> Uri.of_string
1616+1717+ let user_blobs_location did =
1818+ did
1919+ |> Str.global_replace (Str.regexp ":") "_"
2020+ |> (Filename.concat data_dir "blobs" |> Filename.concat)
+44
pegasus/lib/util/html.ml
···11+module type Template = sig
22+ type props
33+44+ val props_of_json : Yojson.Basic.t -> props
55+66+ val props_to_json : props -> Yojson.Basic.t
77+88+ val make : ?key:string -> props:props -> unit -> React.element
99+end
1010+1111+let render_page ?status ?title (type props)
1212+ (template : (module Template with type props = props)) ~props =
1313+ let module Template = (val template : Template with type props = props) in
1414+ let props_json = Template.props_to_json props |> Yojson.Basic.to_string in
1515+ let page_data = Printf.sprintf "window.__PAGE__ = {props: %s};" props_json in
1616+ let app = Template.make ~props () in
1717+ let page =
1818+ Frontend.Layout.make ?title ~favicon:Env.favicon_url ~children:app ()
1919+ in
2020+ Dream.stream ?status
2121+ ~headers:[("Content-Type", "text/html")]
2222+ (fun stream ->
2323+ [%lwt
2424+ let html, subscribe =
2525+ ReactServerDOM.render_html ~skipRoot:false
2626+ ~bootstrapScriptContent:page_data
2727+ ~bootstrapScripts:["/public/client.js"] page
2828+ in
2929+ [%lwt
3030+ let () = Dream.write stream html in
3131+ [%lwt
3232+ let () = Dream.flush stream in
3333+ [%lwt
3434+ let () =
3535+ subscribe (fun chunk ->
3636+ [%lwt
3737+ let () = Dream.write stream chunk in
3838+ Dream.flush stream] )
3939+ in
4040+ Dream.flush stream]]]] )
4141+4242+let make_data_uri ~mimetype ~data =
4343+ let base64_data = data |> Bytes.to_string |> Base64.encode_string in
4444+ Printf.sprintf "data:%s;base64,%s" mimetype base64_data
+58
pegasus/lib/util/http_.ml
···11+let rec get ?(max_redirects = 5) ?(no_drain = false) ?headers uri =
22+ let ua = "pegasus (" ^ Env.host_endpoint ^ ")" in
33+ let headers =
44+ match headers with
55+ | Some headers ->
66+ Http.Header.add_unless_exists headers "User-Agent" ua
77+ | None ->
88+ Http.Header.of_list [("User-Agent", ua)]
99+ in
1010+ let%lwt ans = Cohttp_lwt_unix.Client.get ~headers uri in
1111+ follow_redirect ~max_redirects ~no_drain uri ans
1212+1313+and follow_redirect ~max_redirects ~no_drain request_uri (response, body) =
1414+ let status = Http.Response.status response in
1515+ (* the unconsumed body would otherwise leak memory *)
1616+ let%lwt () =
1717+ if status <> `OK && not no_drain then Cohttp_lwt.Body.drain_body body
1818+ else Lwt.return_unit
1919+ in
2020+ match status with
2121+ | `Permanent_redirect | `Moved_permanently ->
2222+ handle_redirect ~permanent:true ~max_redirects request_uri response
2323+ | `Found | `Temporary_redirect ->
2424+ handle_redirect ~permanent:false ~max_redirects request_uri response
2525+ | _ ->
2626+ Lwt.return (response, body)
2727+2828+and handle_redirect ~permanent ~max_redirects request_uri response =
2929+ if max_redirects <= 0 then failwith "too many redirects"
3030+ else
3131+ let headers = Http.Response.headers response in
3232+ let location = Http.Header.get headers "location" in
3333+ match location with
3434+ | None ->
3535+ failwith "redirection without Location header"
3636+ | Some url ->
3737+ let uri = Uri.of_string url in
3838+ let%lwt () =
3939+ if permanent then
4040+ Logs_lwt.warn (fun m ->
4141+ m "Permanent redirection from %s to %s"
4242+ (Uri.to_string request_uri)
4343+ url )
4444+ else Lwt.return_unit
4545+ in
4646+ get uri ~max_redirects:(max_redirects - 1)
4747+4848+let copy_query req = Dream.all_queries req |> List.map (fun (k, v) -> (k, [v]))
4949+5050+let make_headers headers =
5151+ List.fold_left
5252+ (fun headers (k, v) ->
5353+ match v with
5454+ | Some value ->
5555+ Http.Header.add headers k value
5656+ | None ->
5757+ headers )
5858+ (Http.Header.init ()) headers
+37
pegasus/lib/util/rapper_.ml
···11+ module CID : Rapper.CUSTOM with type t = Cid.t = struct
22+ type t = Cid.t
33+44+ let t =
55+ let encode cid =
66+ try Ok (Cid.to_string cid) with e -> Error (Printexc.to_string e)
77+ in
88+ Caqti_type.(custom ~encode ~decode:Cid.of_string string)
99+ end
1010+1111+ module Blob : Rapper.CUSTOM with type t = bytes = struct
1212+ type t = bytes
1313+1414+ let t =
1515+ let encode blob =
1616+ try Ok (Bytes.to_string blob) with e -> Error (Printexc.to_string e)
1717+ in
1818+ let decode blob =
1919+ try Ok (Bytes.of_string blob) with e -> Error (Printexc.to_string e)
2020+ in
2121+ Caqti_type.(custom ~encode ~decode string)
2222+ end
2323+2424+ module Json : Rapper.CUSTOM with type t = Yojson.Safe.t = struct
2525+ type t = Yojson.Safe.t
2626+2727+ let t =
2828+ let encode json =
2929+ try Ok (Yojson.Safe.to_string json ~std:true)
3030+ with e -> Error (Printexc.to_string e)
3131+ in
3232+ let decode json =
3333+ try Ok (Yojson.Safe.from_string json)
3434+ with e -> Error (Printexc.to_string e)
3535+ in
3636+ Caqti_type.(custom ~encode ~decode string)
3737+ end
+150
pegasus/lib/util/sqlite_.ml
···11+type caqti_pool = (Caqti_lwt.connection, Caqti_error.t) Caqti_lwt_unix.Pool.t
22+33+(* turns a caqti error into an exception *)
44+let caqti_result_exn = function
55+ | Ok x ->
66+ Ok x
77+ | Error caqti_err ->
88+ Error (Caqti_error.Exn caqti_err)
99+1010+let _init_connection (module Db : Rapper_helper.CONNECTION) :
1111+ (unit, Caqti_error.t) Lwt_result.t =
1212+ let open Lwt_result.Syntax in
1313+ let open Caqti_request.Infix in
1414+ let open Caqti_type in
1515+ let* _ =
1616+ Db.find (((unit ->! string) ~oneshot:true) "PRAGMA journal_mode=WAL") ()
1717+ in
1818+ let* _ =
1919+ Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA foreign_keys=ON") ()
2020+ in
2121+ let* _ =
2222+ Db.exec (((unit ->. unit) ~oneshot:true) "PRAGMA synchronous=NORMAL") ()
2323+ in
2424+ let* _ =
2525+ Db.find (((unit ->! int) ~oneshot:true) "PRAGMA busy_timeout=5000") ()
2626+ in
2727+ Lwt.return_ok ()
2828+2929+(* creates an sqlite pool *)
3030+let connect ?(create = false) ?(write = true) db_uri : caqti_pool Lwt.t =
3131+ let uri =
3232+ Uri.add_query_params' db_uri
3333+ [("create", string_of_bool create); ("write", string_of_bool write)]
3434+ in
3535+ let pool_config = Caqti_pool_config.create ~max_size:16 ~max_idle_size:4 () in
3636+ match
3737+ Caqti_lwt_unix.connect_pool ~pool_config ~post_connect:_init_connection uri
3838+ with
3939+ | Ok pool ->
4040+ Lwt.return pool
4141+ | Error e ->
4242+ raise (Caqti_error.Exn e)
4343+4444+let with_connection db_uri f =
4545+ match%lwt
4646+ Caqti_lwt_unix.with_connection db_uri (fun conn ->
4747+ match%lwt _init_connection conn with
4848+ | Ok () ->
4949+ f conn
5050+ | Error e ->
5151+ Lwt.return_error e )
5252+ with
5353+ | Ok result ->
5454+ Lwt.return result
5555+ | Error e ->
5656+ raise (Caqti_error.Exn e)
5757+5858+let use_pool ?(timeout = 60.0) pool
5959+ (f : Caqti_lwt.connection -> ('a, Caqti_error.t) Lwt_result.t) : 'a Lwt.t =
6060+ match%lwt
6161+ Lwt_unix.with_timeout timeout (fun () -> Caqti_lwt_unix.Pool.use f pool)
6262+ with
6363+ | Ok res ->
6464+ Lwt.return res
6565+ | Error e ->
6666+ raise (Caqti_error.Exn e)
6767+6868+let transact conn fn : (unit, 'e) Lwt_result.t =
6969+ let module C = (val conn : Caqti_lwt.CONNECTION) in
7070+ match%lwt C.start () with
7171+ | Ok () -> (
7272+ try%lwt
7373+ match%lwt fn () with
7474+ | Ok _ -> (
7575+ match%lwt C.commit () with
7676+ | Ok () ->
7777+ Lwt.return_ok ()
7878+ | Error e -> (
7979+ match%lwt C.rollback () with
8080+ | Ok () ->
8181+ Lwt.return_error e
8282+ | Error e ->
8383+ Lwt.return_error e ) )
8484+ | Error e -> (
8585+ match%lwt C.rollback () with
8686+ | Ok () ->
8787+ Lwt.return_error e
8888+ | Error e ->
8989+ Lwt.return_error e )
9090+ with e -> (
9191+ match%lwt C.rollback () with
9292+ | Ok () ->
9393+ Lwt.return_error
9494+ ( match e with
9595+ | Caqti_error.Exn e ->
9696+ e
9797+ | e ->
9898+ Caqti_error.request_failed ~query:"unknown"
9999+ ~uri:(Uri.of_string "//unknown")
100100+ (Caqti_error.Msg (Printexc.to_string e)) )
101101+ | Error e ->
102102+ Lwt.return_error e ) )
103103+ | Error e ->
104104+ Lwt.return_error e
105105+106106+(* runs a bunch of queries in a transaction, catches duplicate insertion, returning how many succeeded *)
107107+let multi_query pool
108108+ (queries : (Caqti_lwt.connection -> ('a, Caqti_error.t) Lwt_result.t) list)
109109+ : (int, exn) Lwt_result.t =
110110+ let open Syntax in
111111+ Lwt_result.catch (fun () ->
112112+ use_pool pool (fun connection ->
113113+ let module C = (val connection : Caqti_lwt.CONNECTION) in
114114+ let$! () = C.start () in
115115+ let is_ignorable_error e =
116116+ match (e : Caqti_error.t) with
117117+ | `Request_failed qe | `Response_failed qe -> (
118118+ match Caqti_error.cause (`Request_failed qe) with
119119+ | `Not_null_violation | `Unique_violation ->
120120+ true
121121+ | _ ->
122122+ false )
123123+ | _ ->
124124+ false
125125+ in
126126+ let rec aux acc queries =
127127+ match acc with
128128+ | Error e ->
129129+ Lwt.return_error e
130130+ | Ok count -> (
131131+ match queries with
132132+ | [] ->
133133+ Lwt.return (Ok count)
134134+ | query :: rest -> (
135135+ let%lwt result = query connection in
136136+ match result with
137137+ | Ok _ ->
138138+ aux (Ok (count + 1)) rest
139139+ | Error e ->
140140+ if is_ignorable_error e then aux (Ok count) rest
141141+ else Lwt.return_error e ) )
142142+ in
143143+ let%lwt result = aux (Ok 0) queries in
144144+ match result with
145145+ | Ok count ->
146146+ let$! () = C.commit () in
147147+ Lwt.return_ok count
148148+ | Error e ->
149149+ let%lwt _ = C.rollback () in
150150+ Lwt.return_error e ) )
+50
pegasus/lib/util/syntax.ml
···11+ let unwrap m =
22+ match%lwt m with
33+ | Ok x ->
44+ Lwt.return x
55+ | Error e ->
66+ raise (Caqti_error.Exn e)
77+88+ (* unwraps an Lwt result, raising an exception if there's an error *)
99+ let ( let$! ) m f =
1010+ match%lwt m with Ok x -> f x | Error e -> raise (Caqti_error.Exn e)
1111+1212+ (* unwraps an Lwt result, raising an exception if there's an error *)
1313+ let ( >$! ) m f =
1414+ match%lwt m with
1515+ | Ok x ->
1616+ Lwt.return (f x)
1717+ | Error e ->
1818+ raise (Caqti_error.Exn e)
1919+2020+ let at_uri_regexp =
2121+ Re.Pcre.re
2222+ {|^at:\/\/([a-zA-Z0-9._:%-]+)(?:\/([a-zA-Z0-9-.]+)(?:\/([a-zA-Z0-9._~:@!$&%')(*+,;=-]+))?)?(?:#(\/[a-zA-Z0-9._~:@!$&%')(*+,;=\-[\]\/\\]*))?$|}
2323+ |> Re.compile
2424+2525+ type at_uri =
2626+ {repo: string; collection: string; rkey: string; fragment: string option}
2727+2828+ let parse_at_uri uri =
2929+ match Re.exec_opt at_uri_regexp uri with
3030+ | None ->
3131+ None
3232+ | Some m -> (
3333+ try
3434+ Some
3535+ { repo= Re.Group.get m 1
3636+ ; collection= Re.Group.get m 2
3737+ ; rkey= Re.Group.get m 3
3838+ ; fragment= Re.Group.get_opt m 4 }
3939+ with _ -> None )
4040+4141+ let make_at_uri ~repo ~collection ~rkey ~fragment =
4242+ Printf.sprintf "at://%s/%s/%s%s" repo collection rkey
4343+ (Option.value ~default:"" fragment)
4444+4545+ let nsid_authority nsid =
4646+ match String.rindex_opt nsid '.' with
4747+ | None ->
4848+ nsid
4949+ | Some idx ->
5050+ String.sub nsid 0 idx
+12
pegasus/lib/util/time.ml
···11+let minute = 60 * 1000
22+33+let hour = 60 * minute
44+55+let day = 24 * hour
66+77+(* unix timestamp *)
88+let now_ms () : int = int_of_float (Unix.gettimeofday () *. 1000.)
99+1010+let ms_to_iso8601 ms =
1111+ let s = float_of_int ms /. 1000. in
1212+ Timedesc.(of_timestamp_float_s_exn s |> to_iso8601)
+89
pegasus/lib/util/types.ml
···11+ type string_or_null = string option
22+33+ let string_or_null_to_yojson = function Some s -> `String s | None -> `Null
44+55+ let string_or_null_of_yojson = function
66+ | `String s ->
77+ Ok (Some s)
88+ | `Null ->
99+ Ok None
1010+ | _ ->
1111+ Error "invalid field value"
1212+1313+ type string_or_strings = [`String of string | `Strings of string list]
1414+1515+ let string_or_strings_to_yojson = function
1616+ | `String c ->
1717+ `String c
1818+ | `Strings cs ->
1919+ `List (List.map (fun c -> `String c) cs)
2020+2121+ let string_or_strings_of_yojson = function
2222+ | `String c ->
2323+ Ok (`Strings [c])
2424+ | `List cs ->
2525+ Ok (`Strings (Yojson.Safe.Util.filter_string cs))
2626+ | _ ->
2727+ Error "invalid field value"
2828+2929+ type string_map = (string * string) list
3030+3131+ let string_map_to_yojson = function
3232+ | [] ->
3333+ `Assoc []
3434+ | m ->
3535+ `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
3636+3737+ let string_map_of_yojson = function
3838+ | `Null ->
3939+ Ok []
4040+ | `Assoc m ->
4141+ Ok
4242+ (List.filter_map
4343+ (fun (k, v) ->
4444+ match (k, v) with _, `String s -> Some (k, s) | _, _ -> None )
4545+ m )
4646+ | _ ->
4747+ Error "invalid field value"
4848+4949+ type string_or_string_map = [`String of string | `String_map of string_map]
5050+5151+ let string_or_string_map_to_yojson = function
5252+ | `String c ->
5353+ `String c
5454+ | `String_map m ->
5555+ `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
5656+5757+ let string_or_string_map_of_yojson = function
5858+ | `String c ->
5959+ Ok (`String c)
6060+ | `Assoc m ->
6161+ string_map_of_yojson (`Assoc m) |> Result.map (fun m -> `String_map m)
6262+ | _ ->
6363+ Error "invalid field value"
6464+6565+ type string_or_string_map_or_either_list =
6666+ [ `String of string
6767+ | `String_map of string_map
6868+ | `List of string_or_string_map list ]
6969+7070+ let string_or_string_map_or_either_list_to_yojson = function
7171+ | `String c ->
7272+ `String c
7373+ | `String_map m ->
7474+ `Assoc (List.map (fun (k, v) -> (k, `String v)) m)
7575+ | `List l ->
7676+ `List (List.map string_or_string_map_to_yojson l)
7777+7878+ let string_or_string_map_or_either_list_of_yojson = function
7979+ | `String c ->
8080+ Ok (`String c)
8181+ | `Assoc m ->
8282+ string_map_of_yojson (`Assoc m) |> Result.map (fun m -> `String_map m)
8383+ | `List l ->
8484+ Ok
8585+ (`List
8686+ ( List.map string_or_string_map_of_yojson l
8787+ |> List.filter_map (function Ok x -> Some x | Error _ -> None) ) )
8888+ | _ ->
8989+ Error "invalid field value"
+113
pegasus/lib/util/util.ml
···11+module Constants = Constants
22+33+module Syntax = Syntax
44+55+module Rapper = Rapper_
66+77+module Types = Types
88+99+module Sqlite = Sqlite_
1010+1111+module Time = Time
1212+1313+module Http = Http_
1414+1515+module Html = Html
1616+1717+(* returns all blob refs in a record *)
1818+let rec find_blob_refs (record : Mist.Lex.repo_record) : Mist.Blob_ref.t list =
1919+ let rec aux acc entries =
2020+ List.fold_left
2121+ (fun acc value ->
2222+ match value with
2323+ | `BlobRef blob ->
2424+ blob :: acc
2525+ | `LexMap map ->
2626+ find_blob_refs map @ acc
2727+ | `LexArray arr ->
2828+ aux acc (Array.to_list arr) @ acc
2929+ | _ ->
3030+ acc )
3131+ acc entries
3232+ in
3333+ aux [] (Mist.Lex.String_map.bindings record |> List.map snd)
3434+ |> List.sort_uniq (fun (r1 : Mist.Blob_ref.t) r2 -> Cid.compare r1.ref r2.ref)
3535+3636+let mkfile_p path ~perm =
3737+ Core_unix.mkdir_p (Filename.dirname path) ~perm:0o755 ;
3838+ Core_unix.openfile ~mode:[O_CREAT; O_WRONLY] ~perm path |> Core_unix.close
3939+4040+let sig_matches_some_did_key ~did_keys ~signature ~msg =
4141+ List.find_opt
4242+ (fun key ->
4343+ let raw, (module Curve) =
4444+ Kleidos.parse_multikey_str (String.sub key 8 (String.length key - 8))
4545+ in
4646+ let valid =
4747+ Curve.verify ~pubkey:(Curve.normalize_pubkey_to_raw raw) ~signature ~msg
4848+ in
4949+ valid )
5050+ did_keys
5151+ <> None
5252+5353+let request_ip req =
5454+ Dream.header req "X-Forwarded-For"
5555+ |> Option.value ~default:(Dream.client req)
5656+ |> String.split_on_char ',' |> List.hd |> String.split_on_char ':' |> List.hd
5757+ |> String.trim
5858+5959+let str_contains ~affix str =
6060+ let re = Str.regexp_string affix in
6161+ try
6262+ ignore (Str.search_forward re str 0) ;
6363+ true
6464+ with Not_found -> false
6565+6666+let make_code () =
6767+ let () = Mirage_crypto_rng_unix.use_default () in
6868+ let token =
6969+ Multibase.Base32.encode_string ~pad:false
7070+ @@ Mirage_crypto_rng_unix.getrandom 8
7171+ in
7272+ String.sub token 0 5 ^ "-" ^ String.sub token 5 5
7373+7474+let send_email_or_log ~(recipients : Letters.recipient list) ~subject
7575+ ~(body : Letters.body) =
7676+ let log_email () =
7777+ match body with
7878+ | Plain text | Html text | Mixed (text, _, _) ->
7979+ let to_addr =
8080+ List.find_map
8181+ (fun (r : Letters.recipient) ->
8282+ match r with To addr -> Some addr | _ -> None )
8383+ recipients
8484+ |> Option.get
8585+ in
8686+ Log.info (fun log -> log "email to %s: %s" to_addr text)
8787+ in
8888+ match (Env.smtp_config, Env.smtp_sender) with
8989+ | Some config, Some sender -> (
9090+ match Letters.create_email ~from:sender ~recipients ~subject ~body () with
9191+ | Error e ->
9292+ failwith (Printf.sprintf "failed to construct email: %s" e)
9393+ | Ok message -> (
9494+ try%lwt Letters.send ~config ~sender ~recipients ~message
9595+ with e ->
9696+ Log.log_exn e ;
9797+ Lwt.return (log_email ()) ) )
9898+ | _ ->
9999+ Lwt.return (log_email ())
100100+101101+let s3_error_to_string : Aws_s3_lwt.S3.error -> string = function
102102+ | Redirect endpoint ->
103103+ "redirect to " ^ endpoint.host
104104+ | Throttled ->
105105+ "throttled"
106106+ | Unknown (code, msg) ->
107107+ Printf.sprintf "unknown error %d: %s" code msg
108108+ | Failed exn ->
109109+ Printf.sprintf "failed: %s" (Printexc.to_string exn)
110110+ | Forbidden ->
111111+ "forbidden"
112112+ | Not_found ->
113113+ "not found"
+3-3
pegasus/lib/xrpc.ml
···276276 let signing_key = Kleidos.parse_multikey_str signing_multikey in
277277 let jwt = Jwt.generate_service_jwt ~did ~aud ~lxm ~signing_key in
278278 let path, _ = Dream.split_target (Dream.target ctx.req) in
279279- let query = Util.copy_query ctx.req in
279279+ let query = Util.Http.copy_query ctx.req in
280280 let uri = Uri.make ~scheme ~host ~path ~query () in
281281 let headers =
282282- Util.make_headers
282282+ Util.Http.make_headers
283283 [ ("accept-language", Dream.header ctx.req "accept-language")
284284 ; ("content-type", Dream.header ctx.req "content-type")
285285 ; ( "atproto-accept-labelers"
···291291 Lwt_unix.with_timeout 30.0 (fun () ->
292292 match Dream.method_ ctx.req with
293293 | `GET ->
294294- Util.http_get uri ~headers ~no_drain:true
294294+ Util.Http.get uri ~headers ~no_drain:true
295295 | `POST ->
296296 let%lwt req_body = Dream.body ctx.req in
297297 Client.post uri ~headers ~body:(Body.of_string req_body)
···2424let with_db (f : Data_store.t -> unit Lwt.t) : unit Lwt.t =
2525 let tmp = Filename.temp_file "pegasus_sequencer_test" ".db" in
2626 let%lwt pool =
2727- Util.connect_sqlite ~create:true ~write:true
2727+ Util.Sqlite.connect ~create:true ~write:true
2828 (Uri.of_string ("sqlite3://" ^ tmp))
2929 in
3030 let%lwt () = Migrations.run_migrations Data_store pool in
···7979 with_db (fun conn ->
8080 let did = "did:example:bob" in
8181 (* add 3 identity events to db without publishing to bus *)
8282- let time0 = Util.now_ms () in
8282+ let time0 = Util.Time.now_ms () in
8383 let mk_raw did =
8484 let evt : Sequencer.Types.identity_evt = {did; handle= None} in
8585 Dag_cbor.encode_yojson @@ Sequencer.Encode.format_identity evt
···136136let test_gap_healing () =
137137 with_db (fun conn ->
138138 let did = "did:example:carol" in
139139- let time0 = Util.now_ms () in
139139+ let time0 = Util.Time.now_ms () in
140140 (* add 2 identity events to db without publishing *)
141141 let mk_raw did =
142142 let evt : Sequencer.Types.identity_evt = {did; handle= None} in