src/foodog_gen.erl

-module(foodog_gen).

-export([jti/2, exp/2, iss/2, sub_jwk/2, token/2]).

-spec jti(map(), integer()) -> map().
jti(Payload, N) ->
    Payload#{<<"jti">> => do_random_num(N)}.

-spec do_random_num(integer()) -> binary().
do_random_num(N) ->
    integer_to_binary(rand:uniform(N)).

-spec exp(map(),
          {seconds | minutes | hours | days | weeks | months | years, integer()}) ->
             map().
exp(Payload, Option) ->
    Payload#{<<"exp">> => do_exp(Option)}.

-spec do_exp({seconds | minutes | hours | days | weeks | months | years, integer()}) ->
                integer().
do_exp({seconds, N}) ->
    erlang:system_time(seconds) + N;
do_exp({minutes, N}) ->
    erlang:system_time(seconds) + N * 60;
do_exp({hours, N}) ->
    erlang:system_time(seconds) + N * 60 * 60;
do_exp({days, N}) ->
    erlang:system_time(seconds) + N * 60 * 60 * 24;
do_exp({weeks, N}) ->
    erlang:system_time(seconds) + N * 60 * 60 * 24 * 7;
do_exp({months, N}) ->
    erlang:system_time(seconds) + N * 60 * 60 * 24 * 7 * 4;
do_exp({years, N}) ->
    erlang:system_time(seconds) + N * 60 * 60 * 24 * 365;
do_exp(N) ->
    N.

-spec iss(map(), binary()) -> map().
iss(Payload, Issuer) ->
    Payload#{<<"iss">> => Issuer}.

-spec sub_jwk(map(), binary()) -> map().
sub_jwk(Payload, KeyId) ->
    Payload#{<<"sub_jwk">> => KeyId}.

-spec token(map(), binary()) -> {ok, binary()} | {error, any()}.
token(Payload, Key) ->
    try jose_jwt:sign(
            foodog_util:binary_to_key(Key), #{<<"alg">> => <<"HS256">>}, Payload)
    of
        Signed ->
            {_, Result} = jose_jws:compact(Signed),
            {ok, Result}
    catch
        Err ->
            {error, Err}
    end.

-ifdef(TEST).

-include_lib("eunit/include/eunit.hrl").

jti_test() ->
    #{<<"jti">> := Jti} = jti(#{}, 10),
    ?assert(is_binary(Jti)).

exp_test() ->
    #{<<"exp">> := Exp0} = exp(#{}, {seconds, 1}),
    ?assert(is_integer(Exp0)),

    #{<<"exp">> := Exp1} = exp(#{}, {minutes, 1}),
    ?assert(is_integer(Exp1)),

    #{<<"exp">> := Exp2} = exp(#{}, {hours, 1}),
    ?assert(is_integer(Exp2)),

    #{<<"exp">> := Exp3} = exp(#{}, {days, 1}),
    ?assert(is_integer(Exp3)),

    #{<<"exp">> := Exp4} = exp(#{}, {weeks, 1}),
    ?assert(is_integer(Exp4)),

    #{<<"exp">> := Exp5} = exp(#{}, {months, 1}),
    ?assert(is_integer(Exp5)),

    #{<<"exp">> := Exp6} = exp(#{}, {years, 1}),
    ?assert(is_integer(Exp6)).

iss_test() ->
    #{<<"iss">> := Issuer} = iss(#{}, <<"example.com">>),
    ?assertEqual(<<"example.com">>, Issuer).

sub_jwk_test() ->
    #{<<"sub_jwk">> := Key} = sub_jwk(#{}, <<"123456789">>),
    ?assertEqual(<<"123456789">>, Key).

token_test() ->
    {ok, Token} = token(#{<<"foobar">> => <<"barfoo">>}, <<"123456789">>),
    ?assert(is_binary(Token)).

-endif.