src/erlPass.erl

%% @doc A password generator.
%% @author Robert Lasu
%% @version 0.1.0
%% @copyright 2022 Robert Lasu

-module(erlPass).
-export([generate/5]).

gen_number(B) ->
    integer_to_list(B rem 9).

gen_upper(B) ->
    [65 + (B rem 26)].

gen_lower(B) ->
    [97 + (B rem 26)].

gen_symbol({B, A}) ->
    case B rem 4 of
        0 ->
            [32 + A rem 16];
        1 ->
            [58 + A rem 7];
        2 ->
            [91 + A rem 6];
        3 ->
            [123 + A rem 4]
        end.

seed() ->
    <<A:24, B:24>> = crypto:strong_rand_bytes(6),
    {A,B}.


%% @doc Generates a password.
%% @end
-spec generate(Length, Upper, Lower, Number, Symbol) -> Pass when
    Length  ::integer(),
    Upper   ::boolean(),
    Lower   ::boolean(),
    Number  ::boolean(),
    Symbol  ::boolean(),
    Pass    ::list().
generate(Length,_,_,_,_) when Length < 1 -> {error, invalid_length};
generate(Length, Upper, Lower, Number, Symbol) -> generate(Length, Upper, Lower, Number, Symbol, []).

%% @doc Generate a password
%% see {@link generate/5}
%% @end
-spec generate(Length, Upper, Lower, Number, Symbol, Pass) -> RetPass when
    Length  ::integer(),
    Upper   ::boolean(),
    Lower   ::boolean(),
    Number  ::boolean(),
    Symbol  ::boolean(),
    Pass    ::list(),
    RetPass ::list().
generate(_,false,false,false,false,_) -> {error, no_char};
generate(0,_,_,_,_, Pass) -> lists:flatten(Pass);
generate(Length, Upper, Lower, Number, Symbol, Pass) ->
    {A, B} = seed(),

    case A rem 4 of
        0 -> generate(Number, Length, Upper, Lower, Number, Symbol, fun gen_number/1, B, Pass);
        1 -> generate(Upper, Length, Upper, Lower, Number, Symbol, fun gen_upper/1, B, Pass);
        2 -> generate(Lower, Length, Upper, Lower, Number, Symbol, fun gen_lower/1, B, Pass);
        3 -> generate(Symbol, Length, Upper, Lower, Number, Symbol, fun gen_symbol/1, {B,A}, Pass)
        end.

-spec generate(ToGen, Length, Upper, Lower, Number, Symbol, Fun, Args, Pass) -> RetPass when
    ToGen       :: boolean(),
    Length      :: integer(),
    Upper       :: boolean(),
    Lower       :: boolean(),
    Number      :: boolean(),
    Symbol      :: boolean(),
    Fun         :: function(),
    Args        :: term(),
    Pass        :: list(),
    RetPass     :: list().
generate(_, 0, _,_,_,_,_,_, Pass) -> Pass;
generate(true, Length, U, L, N, S, Fun, B, Pass) -> generate(Length-1, U, L, N, S, [ Fun(B) | Pass]);
generate(false, Length, U, L, N, S, _, _, Pass) -> generate(Length, U, L, N, S, Pass).