Packages
The shared sans-io core of the gleam-atproto client packages: XRPC error vocabulary and response handling, plus the OAuth effect kernel.
Current section
Files
Jump to
Current section
Files
src/atproto_core@oauth@transport.erl
-module(atproto_core@oauth@transport).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/atproto_core/oauth/transport.gleam").
-export([dpop_nonce_challenge/1, post_form_with_dpop/2]).
-if(?OTP_RELEASE >= 27).
-define(MODULEDOC(Str), -moduledoc(Str)).
-define(DOC(Str), -doc(Str)).
-else.
-define(MODULEDOC(Str), -compile([])).
-define(DOC(Str), -compile([])).
-endif.
?MODULEDOC(
" The shared OAuth transport as an `Effect`: a form-encoded POST carrying a\n"
" DPoP proof, with the mandatory nonce retry (first attempt no nonce, retry\n"
" with the server's DPoP-Nonce on `use_dpop_nonce`). `dpop_nonce_challenge`\n"
" is the single, target-agnostic copy of the nonce-detection logic.\n"
).
-file("src/atproto_core/oauth/transport.gleam", 44).
-spec attempt(
binary(),
list({binary(), binary()}),
gleam@option:option(binary())
) -> atproto_core@oauth@effect:effect({ok,
gleam@http@response:response(binary())} |
{error, binary()}).
attempt(Url, Form, Nonce) ->
atproto_core@oauth@effect:'try'(
atproto_core@oauth@effect:proof(<<"POST"/utf8>>, Url, Nonce, none),
fun(Proof) -> case gleam@http@request:to(Url) of
{error, _} ->
atproto_core@oauth@effect:done(
{error, <<"bad url: "/utf8, Url/binary>>}
);
{ok, Base} ->
_pipe@4 = atproto_core@oauth@effect:fetch(
begin
_pipe = Base,
_pipe@1 = gleam@http@request:set_method(_pipe, post),
_pipe@2 = gleam@http@request:set_header(
_pipe@1,
<<"content-type"/utf8>>,
<<"application/x-www-form-urlencoded"/utf8>>
),
_pipe@3 = gleam@http@request:set_header(
_pipe@2,
<<"dpop"/utf8>>,
Proof
),
gleam@http@request:set_body(
_pipe@3,
gleam@uri:query_to_string(Form)
)
end
),
atproto_core@oauth@effect:map_error(
_pipe@4,
fun atproto_core@xrpc:transport_error_to_string/1
)
end end
).
-file("src/atproto_core/oauth/transport.gleam", 31).
?DOC(
" The DPoP nonce a server is asking us to use, if it rejected the request with\n"
" `use_dpop_nonce`. The authorization server (PAR/token) signals this in the\n"
" JSON body; the PDS resource server signals it in the `WWW-Authenticate`\n"
" header. Either way the nonce itself comes in the `DPoP-Nonce` header.\n"
).
-spec dpop_nonce_challenge(gleam@http@response:response(binary())) -> gleam@option:option(binary()).
dpop_nonce_challenge(Resp) ->
Stale = (erlang:element(2, Resp) =:= 400) orelse (erlang:element(2, Resp)
=:= 401),
Www_auth = begin
_pipe = gleam@http@response:get_header(
Resp,
<<"www-authenticate"/utf8>>
),
gleam@result:unwrap(_pipe, <<""/utf8>>)
end,
Signaled = gleam_stdlib:contains_string(
erlang:element(4, Resp),
<<"use_dpop_nonce"/utf8>>
)
orelse gleam_stdlib:contains_string(Www_auth, <<"use_dpop_nonce"/utf8>>),
case Stale andalso Signaled of
true ->
gleam@option:from_result(
gleam@http@response:get_header(Resp, <<"dpop-nonce"/utf8>>)
);
false ->
none
end.
-file("src/atproto_core/oauth/transport.gleam", 16).
-spec post_form_with_dpop(binary(), list({binary(), binary()})) -> atproto_core@oauth@effect:effect({ok,
gleam@http@response:response(binary())} |
{error, binary()}).
post_form_with_dpop(Url, Form) ->
atproto_core@oauth@effect:'try'(
attempt(Url, Form, none),
fun(First) -> case dpop_nonce_challenge(First) of
{some, Nonce} ->
attempt(Url, Form, {some, Nonce});
none ->
atproto_core@oauth@effect:done({ok, First})
end end
).