feat: forgot/reset password API (variant A). Fixes EventHub/EventHubBack#57
This commit is contained in:
@@ -1,8 +1,11 @@
|
||||
-module(logic_email).
|
||||
-export([send_verification_email/2, send_specialist_invite/2]).
|
||||
-export([send_verification_email/2, send_specialist_invite/2, send_password_reset/2]).
|
||||
|
||||
send_verification_email(Email, Token) ->
|
||||
io:format("Sending verification email to ~s with token ~s~n", [Email, Token]).
|
||||
|
||||
send_specialist_invite(Email, Token) ->
|
||||
io:format("Sending specialist invite email to ~s with token ~s~n", [Email, Token]).
|
||||
|
||||
send_password_reset(Email, Token) ->
|
||||
io:format("Sending password reset email to ~s with token ~s~n", [Email, Token]).
|
||||
|
||||
Executable
+61
@@ -0,0 +1,61 @@
|
||||
-module(logic_password_reset).
|
||||
-include("records.hrl").
|
||||
-export([request_reset/1, reset_password/2]).
|
||||
|
||||
-define(MIN_PASSWORD_LEN, 8).
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc Запрос сброса пароля. Всегда `{ok, sent}` — без enumeration.
|
||||
%%% Письмо (stub) уходит только для `active` пользователей.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-spec request_reset(Email :: binary()) -> {ok, sent}.
|
||||
request_reset(Email) when is_binary(Email) ->
|
||||
case core_user:get_by_email(Email) of
|
||||
{ok, #user{id = UserId, status = active, email = UserEmail}} ->
|
||||
{ok, Token, _Expires} = core_password_reset:create_token(UserId),
|
||||
logic_email:send_password_reset(UserEmail, Token),
|
||||
{ok, sent};
|
||||
_ ->
|
||||
{ok, sent}
|
||||
end;
|
||||
request_reset(_) ->
|
||||
{ok, sent}.
|
||||
|
||||
%%%-------------------------------------------------------------------
|
||||
%%% @doc Установка нового пароля по токену. Отзывает refresh-сессии user.
|
||||
%%% @end
|
||||
%%%-------------------------------------------------------------------
|
||||
-spec reset_password(Token :: binary(), Password :: binary()) ->
|
||||
ok | {error, expired | not_found | invalid_password | password_hash_failed | user_not_found | forbidden}.
|
||||
reset_password(Token, Password)
|
||||
when is_binary(Token), is_binary(Password), byte_size(Password) >= ?MIN_PASSWORD_LEN ->
|
||||
case core_password_reset:verify_token(Token) of
|
||||
{ok, UserId} ->
|
||||
case core_user:get_by_id(UserId) of
|
||||
{ok, #user{status = active}} ->
|
||||
case logic_auth:hash_password(Password) of
|
||||
{ok, NewHash} ->
|
||||
case core_user:update(UserId, [{password_hash, NewHash}]) of
|
||||
{ok, _} ->
|
||||
core_password_reset:delete_token(Token),
|
||||
core_auth_session:revoke_all_for_subject(UserId, user),
|
||||
ok;
|
||||
{error, not_found} ->
|
||||
{error, user_not_found};
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end;
|
||||
{error, _} ->
|
||||
{error, password_hash_failed}
|
||||
end;
|
||||
{ok, #user{}} ->
|
||||
{error, forbidden};
|
||||
{error, not_found} ->
|
||||
{error, user_not_found}
|
||||
end;
|
||||
{error, _} = Err ->
|
||||
Err
|
||||
end;
|
||||
reset_password(_, _) ->
|
||||
{error, invalid_password}.
|
||||
Reference in New Issue
Block a user