objective categorical abstract machine language personal data server

Return correct use_dpop_nonce status depending on endpoint

futur.blue fd38dacc 7a7e753c

verified
Changed files
+30 -11
pegasus
+2 -2
pegasus/lib/auth.ml
··· 258 258 ~url:(Dream.target req) ~dpop_header () 259 259 with 260 260 | Error "use_dpop_nonce" -> 261 - Lwt.return_error @@ Errors.use_dpop_nonce () 261 + Lwt.return_error @@ Errors.use_dpop_nonce_auth () 262 262 | Error e -> 263 263 Log.debug (fun log -> log "dpop error: %s" e) ; 264 264 Lwt.return_error @@ Errors.invalid_request ("dpop error: " ^ e) ··· 279 279 ~access_token:token () 280 280 with 281 281 | Error "use_dpop_nonce" -> 282 - Lwt.return_error @@ Errors.use_dpop_nonce () 282 + Lwt.return_error @@ Errors.use_dpop_nonce_resource () 283 283 | Error e -> 284 284 Log.debug (fun log -> log "dpop error: %s" e) ; 285 285 Lwt.return_error @@ Errors.invalid_request ("dpop error: " ^ e)
+18 -5
pegasus/lib/errors.ml
··· 8 8 9 9 exception Redirect of string 10 10 11 - exception UseDpopNonceError 11 + (* HTTP 400, { error: "use_dpop_nonce" } — https://datatracker.ietf.org/doc/html/rfc9449#section-8 *) 12 + exception UseDpopNonceAuthError 13 + 14 + (* HTTP 401, WWW-Authenticate — https://datatracker.ietf.org/doc/html/rfc9449#section-9 *) 15 + exception UseDpopNonceResourceError 12 16 13 17 let is_xrpc_error = function 14 18 | InvalidRequestError _ ··· 30 34 31 35 let not_found ?(name = "NotFound") msg = raise (NotFoundError (name, msg)) 32 36 33 - let use_dpop_nonce () = raise UseDpopNonceError 37 + let use_dpop_nonce_auth () = raise UseDpopNonceAuthError 38 + 39 + let use_dpop_nonce_resource () = raise UseDpopNonceResourceError 34 40 35 41 let printer = function 36 42 | InvalidRequestError (error, message) -> ··· 41 47 Some (Printf.sprintf "Auth error (%s): %s" error message) 42 48 | NotFoundError (error, message) -> 43 49 Some (Printf.sprintf "Not found (%s): %s" error message) 44 - | UseDpopNonceError -> 50 + | UseDpopNonceAuthError -> 51 + Some "Use DPoP nonce" 52 + | UseDpopNonceResourceError -> 45 53 Some "Use DPoP nonce" 46 54 | _ -> 47 55 None ··· 64 72 | NotFoundError (error, message) -> 65 73 Log.debug (fun log -> log "not found error: %s - %s" error message) ; 66 74 format_response error message `Not_Found 67 - | UseDpopNonceError -> 68 - Log.debug (fun log -> log "use_dpop_nonce error") ; 75 + | UseDpopNonceAuthError -> 76 + Log.debug (fun log -> log "use_dpop_nonce auth error") ; 69 77 Dream.json ~status:`Bad_Request 78 + ~headers:[("Access-Control-Expose-Headers", "DPoP-Nonce")] 79 + {|{ "error": "use_dpop_nonce" }|} 80 + | UseDpopNonceResourceError -> 81 + Log.debug (fun log -> log "use_dpop_nonce resource error") ; 82 + Dream.json ~status:`Unauthorized 70 83 ~headers: 71 84 [ ("WWW-Authenticate", {|DPoP error="use_dpop_nonce"|}) 72 85 ; ("Access-Control-Expose-Headers", "DPoP-Nonce, WWW-Authenticate") ]
+10 -4
pegasus/lib/xrpc.ml
··· 107 107 Dream.set_header res "DPoP-Nonce" (Oauth.Dpop.next_nonce ()) 108 108 in 109 109 let () = 110 + let to_expose = 111 + (* see comments on UseDpopNonce____Error in errors.ml *) 112 + if Dream.status res = `Unauthorized then "DPoP-Nonce, WWW-Authenticate" 113 + else if Dream.status res = `Bad_Request then "DPoP-Nonce" 114 + else "" 115 + in 110 116 match Dream.header res "Access-Control-Expose-Headers" with 111 117 | Some header when Util.str_contains ~affix:"DPoP-Nonce" header -> 112 118 () 113 119 | Some header -> 114 120 Dream.set_header res "Access-Control-Expose-Headers" 115 - (header ^ ", DPoP-Nonce") 121 + (header ^ ", " ^ to_expose) 116 122 | _ -> 117 - Dream.set_header res "Access-Control-Expose-Headers" "DPoP-Nonce" 123 + Dream.set_header res "Access-Control-Expose-Headers" to_expose 118 124 in 119 125 res 120 126 ··· 140 146 let%lwt res = exn_to_response e in 141 147 Lwt.return 142 148 ( match e with 143 - | UseDpopNonceError -> 149 + | UseDpopNonceAuthError | UseDpopNonceResourceError -> 144 150 add_dpop_nonce_if_needed res 145 151 | _ -> 146 152 res ) ··· 149 155 Dream.redirect init.req r 150 156 | Rate_limiter.Rate_limit_exceeded status -> 151 157 rate_limit_response status 152 - | UseDpopNonceError as e -> 158 + | (UseDpopNonceAuthError | UseDpopNonceResourceError) as e -> 153 159 let%lwt res = exn_to_response e in 154 160 Lwt.return (add_dpop_nonce_if_needed res) 155 161 | e ->