-module(foodog).
-export([generate/1, generate/2, verify/1, verify/2]).
-spec generate(map()) -> {ok, binary()} | {error, any()}.
generate(Payload0) ->
generate(Payload0, #{}).
-spec generate(map(), map()) -> {ok, binary()} | {error, any()}.
generate(Payload0, Options) ->
Payload1 = foodog_gen:jti(Payload0, maps:get(jti, Options, 1000000000)),
Payload2 = foodog_gen:exp(Payload1, maps:get(exp, Options, {hours, 1})),
case maps:get(iss, Options, issuer()) of
{error, _Err} = E ->
E;
Issuer ->
Payload3 = foodog_gen:iss(Payload2, Issuer),
case keys() of
{error, _Err} = E ->
E;
{ok, []} ->
{error, keys_empty};
{ok, Keys} ->
[{Kid, Key} | _] = Keys,
Payload4 = foodog_gen:sub_jwk(Payload3, Kid),
foodog_gen:token(Payload4, Key)
end
end.
-spec verify(binary()) -> {ok, map()} | {error, any()}.
verify(Token) ->
verify(Token, #{}).
-spec verify(binary(), map()) -> {ok, map()} | {error, any()}.
verify(Token, Options) ->
case verify_key(Token) of
{error, _Err} = E ->
E;
{ok, Payload} ->
case foodog_ver:exp(Payload) of
{error, _Err} = E ->
E;
{ok, _} ->
verify_issuer(Payload, Options)
end
end.
-spec verify_key(binary()) -> {ok, map()} | {error, any()}.
verify_key(Token) ->
case keys() of
{error, _Err} = E ->
E;
{ok, []} ->
{error, keys_empty};
{ok, Keys} ->
case get_key(Token, Keys) of
{error, _Err} = E ->
E;
{ok, Key} ->
foodog_ver:key(Token, Key)
end
end.
-spec get_key(binary(), list()) -> {ok, binary()} | {error, any()}.
get_key(Token, Keys) ->
case foodog_ver:fields(Token) of
{error, _Err} = E ->
E;
{ok, #{<<"sub_jwk">> := Kid}} ->
case proplists:get_value(Kid, Keys) of
undefined ->
{error, key_not_found};
Key ->
{ok, Key}
end;
_ ->
{error, invalid_key_format}
end.
-spec verify_issuer(map(), map()) -> {ok, map()} | {error, any()}.
verify_issuer(Payload, Options) ->
case maps:get(iss, Options, issuer()) of
{error, _Err} = E ->
E;
Issuer ->
case foodog_ver:iss(Payload, Issuer) of
{error, _Err} = E ->
E;
{ok, _Payload} = Result ->
Result
end
end.
-spec issuer() -> binary() | {error, any()}.
issuer() ->
case application:get_env(foodog, issuer) of
undefined ->
{error, undefined_issuer};
{ok, Issuer} ->
Issuer
end.
-spec keys() -> {ok, list()} | {error, any()}.
keys() ->
case application:get_env(foodog, keys) of
undefined ->
{error, undefined_keys};
Keys ->
Keys
end.