Current section
Files
Jump to
Current section
Files
src/ywt@internal@jwt.erl
-module(ywt@internal@jwt).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ywt/internal/jwt.gleam").
-export([encode/4, decode/6, decode_unsafely_without_validation/2]).
-export_type([header/0]).
-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(false).
-type header() :: {header,
ywt@algorithm:algorithm(),
gleam@option:option(binary())}.
-file("src/ywt/internal/jwt.gleam", 29).
?DOC(false).
-spec encode_header(
ywt@algorithm:algorithm(),
gleam@option:option(binary()),
list(ywt@claim:claim())
) -> gleam@json:json().
encode_header(Alg, Kid, Claims) ->
Fields = [{<<"alg"/utf8>>, ywt@algorithm:to_json(Alg)}],
Fields@1 = case Kid of
{some, Kid@1} ->
[{<<"kid"/utf8>>, gleam@json:string(Kid@1)} | Fields];
none ->
Fields
end,
ywt@claim:encode_header(Claims, Fields@1).
-file("src/ywt/internal/jwt.gleam", 165).
?DOC(false).
-spec verify_loop(
list(ywt@verify_key:verify_key()),
boolean(),
fun((ywt@verify_key:verify_key(), fun((boolean()) -> FDF)) -> FDF),
fun((boolean()) -> FDF)
) -> FDF.
verify_loop(Keys, Result, Verify, On_result) ->
case Keys of
[] ->
On_result(Result);
[Key | Keys@1] ->
Verify(
Key,
fun(Is_valid) ->
Result@1 = Result orelse Is_valid,
verify_loop(Keys@1, Result@1, Verify, On_result)
end
)
end.
-file("src/ywt/internal/jwt.gleam", 182).
?DOC(false).
-spec split(binary()) -> {ok, {binary(), binary(), binary()}} |
{error, ywt@internal@core:parse_error()}.
split(Jwt) ->
case gleam@string:split(Jwt, <<"."/utf8>>) of
[Header, Payload, Signature] ->
{ok, {Header, Payload, Signature}};
_ ->
{error, malformed_token}
end.
-file("src/ywt/internal/jwt.gleam", 211).
?DOC(false).
-spec key_matches_header(ywt@verify_key:verify_key(), header()) -> boolean().
key_matches_header(Key, Header) ->
Key_alg = ywt@verify_key:algorithm(Key),
case {erlang:element(3, Header), ywt@verify_key:id(Key)} of
{{some, Header_kid}, {ok, Key_id}} ->
(Header_kid =:= Key_id) andalso (Key_alg =:= erlang:element(
2,
Header
));
{{some, _}, {error, _}} ->
false;
{_, _} ->
Key_alg =:= erlang:element(2, Header)
end.
-file("src/ywt/internal/jwt.gleam", 259).
?DOC(false).
-spec encode_json(gleam@json:json()) -> binary().
encode_json(Part) ->
gleam@bit_array:base64_url_encode(
<<(gleam@json:to_string(Part))/binary>>,
false
).
-file("src/ywt/internal/jwt.gleam", 239).
?DOC(false).
-spec encode(
list({binary(), gleam@json:json()}),
list(ywt@claim:claim()),
ywt@sign_key:sign_key(),
fun((bitstring(), ywt@sign_key:sign_key(), fun((bitstring()) -> binary())) -> FDM)
) -> FDM.
encode(Payload, Claims, Key, Sign) ->
Alg = ywt@sign_key:algorithm(Key),
Header = encode_json(
encode_header(
Alg,
gleam@option:from_result(ywt@sign_key:id(Key)),
Claims
)
),
Payload@1 = encode_json(ywt@claim:encode(Claims, Payload)),
Verify_message = <<<<Header/binary, "."/utf8>>/binary, Payload@1/binary>>,
Sign(
<<Verify_message/binary>>,
Key,
fun(Signed) ->
Signature = gleam@bit_array:base64_url_encode(Signed, false),
<<<<Verify_message/binary, "."/utf8>>/binary, Signature/binary>>
end
).
-file("src/ywt/internal/jwt.gleam", 69).
?DOC(false).
-spec decode(
binary(),
gleam@dynamic@decode:decoder(FCX),
list(ywt@claim:claim()),
list(ywt@verify_key:verify_key()),
fun((bitstring(), bitstring(), ywt@verify_key:verify_key(), fun((boolean()) -> FDB)) -> FDB),
fun(({ok, FCX} | {error, ywt@internal@core:parse_error()}) -> FDB)
) -> FDB.
decode(Jwt, Decoder, Claims, Keys, Verify, Resolve) ->
Continuation_or_error = begin
gleam@result:'try'(
split(Jwt),
fun(_use0) ->
{Raw_header, Raw_payload, Raw_signature} = _use0,
gleam@result:'try'(
part(
Raw_header,
invalid_header_encoding,
fun(Field@0) -> {invalid_header_json, Field@0} end
),
fun(Dynamic_header) ->
gleam@result:'try'(
begin
_pipe = gleam@dynamic@decode:run(
Dynamic_header,
header_decoder()
),
gleam@result:map_error(
_pipe,
fun(Error) ->
{invalid_header_json,
{unable_to_decode, Error}}
end
)
end,
fun(Parsed_header) ->
gleam@result:'try'(
part(
Raw_payload,
invalid_payload_encoding,
fun(Field@0) -> {invalid_payload_json, Field@0} end
),
fun(Dynamic_payload) ->
gleam@result:'try'(
ywt@claim:verify_with_header(
Dynamic_header,
Dynamic_payload,
Claims
),
fun(_use0@1) ->
nil = _use0@1,
gleam@result:'try'(
begin
_pipe@1 = gleam@dynamic@decode:run(
Dynamic_payload,
Decoder
),
gleam@result:map_error(
_pipe@1,
fun(Field@0) -> {payload_decoding_error, Field@0} end
)
end,
fun(Parsed_payload) ->
gleam@result:'try'(
begin
_pipe@2 = gleam@bit_array:base64_url_decode(
Raw_signature
),
gleam@result:replace_error(
_pipe@2,
invalid_signature_encoding
)
end,
fun(Signature) ->
Matching_keys = gleam@list:filter(
Keys,
fun(
_capture
) ->
key_matches_header(
_capture,
Parsed_header
)
end
),
gleam@bool:guard(
gleam@list:is_empty(
Matching_keys
),
{error,
no_matching_key},
fun() ->
Verify_message = <<Raw_header/binary,
"."/utf8,
Raw_payload/binary>>,
Verify@1 = fun(
Key,
Next
) ->
Verify(
Verify_message,
Signature,
Key,
Next
)
end,
On_result = fun(
Result
) ->
case Result of
true ->
Resolve(
{ok,
Parsed_payload}
);
false ->
Resolve(
{error,
invalid_signature}
)
end
end,
{ok,
fun(
) ->
verify_loop(
Matching_keys,
false,
Verify@1,
On_result
)
end}
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end
)
end,
case Continuation_or_error of
{ok, Continuation} ->
Continuation();
{error, Error@1} ->
Resolve({error, Error@1})
end.
-file("src/ywt/internal/jwt.gleam", 190).
?DOC(false).
-spec part(
binary(),
ywt@internal@core:parse_error(),
fun((gleam@json:decode_error()) -> ywt@internal@core:parse_error())
) -> {ok, gleam@dynamic:dynamic_()} | {error, ywt@internal@core:parse_error()}.
part(Part, Encoding_error, Json_error) ->
gleam@result:'try'(
begin
_pipe = gleam@bit_array:base64_url_decode(Part),
gleam@result:replace_error(_pipe, Encoding_error)
end,
fun(Decoded) ->
_pipe@1 = gleam@json:parse_bits(
Decoded,
{decoder, fun gleam@dynamic@decode:decode_dynamic/1}
),
gleam@result:map_error(_pipe@1, Json_error)
end
).
-file("src/ywt/internal/jwt.gleam", 22).
?DOC(false).
-spec header_decoder() -> gleam@dynamic@decode:decoder(header()).
header_decoder() ->
gleam@dynamic@decode:field(
<<"alg"/utf8>>,
ywt@algorithm:decoder(),
fun(Alg) ->
gleam@dynamic@decode:optional_field(
<<"kid"/utf8>>,
none,
gleam@dynamic@decode:map(
{decoder, fun gleam@dynamic@decode:decode_string/1},
fun(Field@0) -> {some, Field@0} end
),
fun(Kid) -> gleam@dynamic@decode:success({header, Alg, Kid}) end
)
end
).
-file("src/ywt/internal/jwt.gleam", 48).
?DOC(false).
-spec decode_unsafely_without_validation(
binary(),
gleam@dynamic@decode:decoder(FCT)
) -> {ok, FCT} | {error, nil}.
decode_unsafely_without_validation(Jwt, Payload_decoder) ->
Result = begin
gleam@result:'try'(
split(Jwt),
fun(_use0) ->
{_, Raw_payload, _} = _use0,
gleam@result:'try'(
part(
Raw_payload,
invalid_payload_encoding,
fun(Field@0) -> {invalid_payload_json, Field@0} end
),
fun(Dynamic_payload) ->
_pipe = gleam@dynamic@decode:run(
Dynamic_payload,
Payload_decoder
),
gleam@result:map_error(
_pipe,
fun(Field@0) -> {payload_decoding_error, Field@0} end
)
end
)
end
)
end,
gleam@result:replace_error(Result, nil).