objective categorical abstract machine language personal data server
65
fork

Configure Feed

Select the types of activity you want to include in your feed.

Multi account session support

futurGH 9b7df25f c48efaf4

+144 -48
+1 -1
pegasus/lib/api/account_/login.ml
··· 33 33 ~props:{redirect_url; csrf_token; error= Some error} 34 34 | Some {did; _} -> 35 35 let%lwt () = Dream.invalidate_session ctx.req in 36 - let%lwt () = Dream.set_session_field ctx.req "did" did in 36 + let%lwt () = Session.log_in_did ctx.req did in 37 37 Dream.redirect ctx.req redirect_url ) 38 38 | _ -> 39 39 let redirect_url = "/account" in
+53 -44
pegasus/lib/api/oauth_/authorize.ml
··· 1 1 open Oauth 2 2 open Oauth.Types 3 3 4 - let get_session_user (ctx : Xrpc.context) = 5 - match Dream.session_field ctx.req "did" with 6 - | Some did -> 7 - Lwt.return_some did 8 - | None -> 9 - Lwt.return_none 10 - 11 4 let get_handler = 12 5 Xrpc.handler (fun ctx -> 13 6 let login_redirect = ··· 62 55 ; expires_at 63 56 ; used= false } 64 57 in 65 - match%lwt get_session_user ctx with 58 + match%lwt Session.Raw.get_session ctx.req with 66 59 | None -> 67 60 login_redirect 68 - | Some did -> ( 69 - match req.login_hint with 70 - | Some hint when hint <> did -> 71 - login_redirect 72 - | _ -> 73 - let%lwt handle = 74 - match%lwt 75 - Data_store.get_actor_by_identifier did ctx.db 76 - with 77 - | Some {handle; _} -> 78 - Lwt.return handle 79 - | None -> 80 - Errors.internal_error 81 - ~msg:"failed to resolve user" () 82 - in 83 - let scopes = String.split_on_char ' ' req.scope in 84 - let csrf_token = Dream.csrf_token ctx.req in 85 - let client_id_uri = Uri.of_string metadata.client_id in 86 - let host, path = 87 - ( Uri.host_with_default client_id_uri 88 - ~default:"unknown" 89 - , Uri.path client_id_uri ) 90 - in 91 - let client_url = (host, path) in 92 - let client_name = metadata.client_name in 93 - Util.render_html ~title:("Authorizing " ^ host) 94 - (module Frontend.OauthAuthorizePage) 95 - ~props: 96 - { client_url 97 - ; client_name 98 - ; handle 99 - ; scopes 100 - ; code 101 - ; request_uri 102 - ; csrf_token } ) ) ) ) 61 + | Some session when session.logged_in_dids = [] -> 62 + login_redirect 63 + | Some {current_did; logged_in_dids} -> ( 64 + let%lwt did = 65 + match req.login_hint with 66 + | Some hint when List.mem hint logged_in_dids -> 67 + let%lwt () = 68 + if Some hint <> current_did then 69 + Session.Raw.set_current_did ctx.req hint 70 + else Lwt.return_unit 71 + in 72 + Lwt.return_some hint 73 + | _ -> 74 + Lwt.return current_did 75 + in 76 + match did with 77 + | None -> 78 + login_redirect 79 + | Some did -> 80 + let%lwt handle = 81 + match%lwt 82 + Data_store.get_actor_by_identifier did ctx.db 83 + with 84 + | Some {handle; _} -> 85 + Lwt.return handle 86 + | None -> 87 + Errors.internal_error 88 + ~msg:"failed to resolve user" () 89 + in 90 + let scopes = String.split_on_char ' ' req.scope in 91 + let csrf_token = Dream.csrf_token ctx.req in 92 + let client_id_uri = 93 + Uri.of_string metadata.client_id 94 + in 95 + let host, path = 96 + ( Uri.host_with_default client_id_uri 97 + ~default:"unknown" 98 + , Uri.path client_id_uri ) 99 + in 100 + let client_url = (host, path) in 101 + let client_name = metadata.client_name in 102 + Util.render_html ~title:("Authorizing " ^ host) 103 + (module Frontend.OauthAuthorizePage) 104 + ~props: 105 + { client_url 106 + ; client_name 107 + ; handle 108 + ; scopes 109 + ; code 110 + ; request_uri 111 + ; csrf_token } ) ) ) ) 103 112 104 113 let post_handler = 105 114 Xrpc.handler (fun ctx -> 106 - match%lwt get_session_user ctx with 115 + match%lwt Session.Raw.get_current_did ctx.req with 107 116 | None -> 108 117 Errors.auth_required "missing authentication" 109 118 | Some user_did -> (
+1
pegasus/lib/api/oauth_/token.ml
··· 170 170 Queries.update_oauth_token ctx.db 171 171 ~old_refresh_token:refresh_token 172 172 ~new_refresh_token:new_refresh ~expires_at:new_expires_at 173 + ~ip ~user_agent 173 174 in 174 175 Dream.json ~headers:[("Cache-Control", "no-store")] 175 176 @@ Yojson.Safe.to_string
+5 -3
pegasus/lib/oauth/queries.ml
··· 103 103 record_out] 104 104 ~refresh_token 105 105 106 - let update_oauth_token conn ~old_refresh_token ~new_refresh_token ~expires_at = 106 + let update_oauth_token conn ~old_refresh_token ~new_refresh_token ~expires_at 107 + ~ip ~user_agent = 107 108 Util.use_pool conn 108 109 @@ [%rapper 109 110 execute 110 111 {sql| 111 112 UPDATE oauth_tokens 112 113 SET refresh_token = %string{new_refresh_token}, 113 - expires_at = %int{expires_at} 114 + expires_at = %int{expires_at}, last_ip = %string{ip}, 115 + last_user_agent = %string?{user_agent} 114 116 WHERE refresh_token = %string{old_refresh_token} 115 117 |sql}] 116 - ~new_refresh_token ~expires_at ~old_refresh_token 118 + ~new_refresh_token ~expires_at ~old_refresh_token ~ip ~user_agent 117 119 118 120 let delete_oauth_token_by_refresh conn refresh_token = 119 121 Util.use_pool conn
+84
pegasus/lib/session.ml
··· 1 + type data = 2 + { current_did: string option [@default None] 3 + ; logged_in_dids: string list [@default []] } 4 + [@@deriving yojson {strict= false}] 5 + 6 + let default = {current_did= None; logged_in_dids= []} 7 + 8 + module Raw = struct 9 + let set_session req data = 10 + Dream.set_session_field req "pegasus.session" 11 + (data_to_yojson data |> Yojson.Safe.to_string) 12 + 13 + let get_session req = 14 + match Dream.session_field req "pegasus.session" with 15 + | Some data -> ( 16 + match 17 + data_of_yojson (try Yojson.Safe.from_string data with _ -> `Null) 18 + with 19 + | Ok data -> 20 + Lwt.return_some data 21 + | Error _ -> 22 + let%lwt () = set_session req default in 23 + Lwt.return_some default ) 24 + | None -> 25 + Lwt.return_none 26 + 27 + let clear_session req = Dream.set_session_field req "pegasus.session" "" 28 + 29 + let get_current_did req = 30 + match%lwt get_session req with 31 + | Some {current_did; _} when current_did <> None -> 32 + Lwt.return current_did 33 + | _ -> 34 + Lwt.return_none 35 + 36 + let set_current_did req did = 37 + match%lwt get_session req with 38 + | Some {logged_in_dids; _} -> 39 + let%lwt () = set_session req {current_did= Some did; logged_in_dids} in 40 + Lwt.return_unit 41 + | None -> 42 + Lwt.return_unit 43 + 44 + let get_logged_in_dids req = 45 + match%lwt get_session req with 46 + | Some {logged_in_dids; _} -> 47 + Lwt.return logged_in_dids 48 + | None -> 49 + Lwt.return [] 50 + 51 + let set_logged_in_dids req dids = 52 + match%lwt get_session req with 53 + | Some {current_did; _} -> 54 + let%lwt () = set_session req {current_did; logged_in_dids= dids} in 55 + Lwt.return_unit 56 + | None -> 57 + Lwt.return_unit 58 + end 59 + 60 + open Raw 61 + 62 + let log_in_did ?(set_current = true) req did = 63 + match%lwt get_session req with 64 + | Some {current_did; logged_in_dids} -> 65 + let%lwt () = 66 + set_session req 67 + { current_did= (if set_current then Some did else current_did) 68 + ; logged_in_dids= did :: logged_in_dids } 69 + in 70 + Lwt.return_unit 71 + | None -> 72 + Lwt.return_unit 73 + 74 + let log_out_did req did = 75 + match%lwt get_session req with 76 + | Some {current_did; logged_in_dids} -> 77 + let%lwt () = 78 + set_session req 79 + { current_did 80 + ; logged_in_dids= List.filter (fun d -> d <> did) logged_in_dids } 81 + in 82 + Lwt.return_unit 83 + | None -> 84 + Lwt.return_unit