-module(logic_auth). -export([hash_password/1, verify_password/2]). -export([generate_jwt/2, verify_jwt/1, extract_claims/1]). -export([generate_refresh_token/1]). %% ============ Argon2 хеширование ============ hash_password(Password) when is_binary(Password) -> argon2:hash(Password). verify_password(Password, Hash) when is_binary(Password), is_binary(Hash) -> argon2:verify(Password, Hash). %% ============ JWT с использованием jose ============ get_jwt_secret() -> <<"my-super-secret-key-for-jwt-32-bytes!">>. get_jwk() -> jose_jwk:from_oct(get_jwt_secret()). generate_jwt(UserId, Role) -> JWK = get_jwk(), ExpTime = os:system_time(seconds) + 86400, % 24 часа Claims = #{ <<"user_id">> => UserId, <<"role">> => Role, <<"exp">> => ExpTime, <<"iat">> => os:system_time(seconds) }, JWT = jose_jwt:sign(JWK, #{<<"alg">> => <<"HS256">>}, Claims), {_, Token} = jose_jws:compact(JWT), Token. verify_jwt(Token) when is_binary(Token) -> try JWK = get_jwk(), case jose_jwt:verify(JWK, Token) of {true, {jose_jwt, Claims}, _} -> case check_expiry(Claims) of true -> {ok, Claims}; false -> {error, expired} end; {true, Claims, _} when is_map(Claims) -> case check_expiry(Claims) of true -> {ok, Claims}; false -> {error, expired} end; {false, _, _} -> {error, invalid_signature} end catch _:_ -> {error, invalid_token} end. extract_claims(Token) when is_binary(Token) -> try JWK = get_jwk(), case jose_jwt:verify(JWK, Token) of {true, {jose_jwt, Claims}, _} -> {ok, Claims}; {true, Claims, _} when is_map(Claims) -> {ok, Claims}; _ -> {error, invalid_token} end catch _:_ -> {error, invalid_token} end. check_expiry(Claims) -> case maps:find(<<"exp">>, Claims) of {ok, Exp} when is_integer(Exp) -> Exp > os:system_time(seconds); _ -> false end. %% ============ Refresh Token ============ generate_refresh_token(_UserId) -> Token = base64:encode(crypto:strong_rand_bytes(32)), ExpiresAt = calendar:universal_time_to_local_time( calendar:gregorian_seconds_to_datetime( calendar:datetime_to_gregorian_seconds(calendar:universal_time()) + 30 * 86400 ) ), {Token, ExpiresAt}.