-module(handler_refresh). -include("records.hrl"). -export([init/2]). init(Req, Opts) -> handle(Req, Opts). handle(Req, _Opts) -> case cowboy_req:method(Req) of <<"POST">> -> {ok, Body, Req1} = cowboy_req:read_body(Req), case jsx:decode(Body, [return_maps]) of #{<<"refresh_token">> := RefreshToken} -> case validate_refresh_token(RefreshToken) of {ok, UserId} -> case core_user:get_by_id(UserId) of {ok, User} -> % Генерируем новые токены NewToken = logic_auth:generate_jwt(User#user.id, User#user.role), {NewRefreshToken, ExpiresAt} = logic_auth:generate_refresh_token(User#user.id), % Сохраняем новый refresh token save_refresh_token(User#user.id, NewRefreshToken, ExpiresAt), % Удаляем старый refresh token delete_refresh_token(RefreshToken), Response = #{ token => NewToken, refresh_token => NewRefreshToken }, send_json(Req1, 200, Response); {error, not_found} -> send_error(Req1, 401, <<"User not found">>) end; {error, expired} -> send_error(Req1, 401, <<"Refresh token expired">>); {error, invalid} -> send_error(Req1, 401, <<"Invalid refresh token">>) end; _ -> send_error(Req1, 400, <<"Missing refresh_token">>) end; _ -> send_error(Req, 405, <<"Method not allowed">>) end. validate_refresh_token(Token) -> case get_session_by_token(Token) of {ok, Session} -> % Проверяем срок действия Now = calendar:universal_time(), case Session#session.expires_at > Now of true -> {ok, Session#session.user_id}; false -> {error, expired} end; {error, not_found} -> {error, invalid} end. get_session_by_token(Token) -> Match = #session{token = Token, type = refresh, _ = '_'}, case mnesia:dirty_match_object(Match) of [] -> {error, not_found}; [Session] -> {ok, Session} end. save_refresh_token(UserId, Token, ExpiresAt) -> Session = #session{ token = Token, user_id = UserId, expires_at = ExpiresAt, type = refresh }, mnesia:dirty_write(Session). delete_refresh_token(Token) -> Match = #session{token = Token, type = refresh, _ = '_'}, case mnesia:dirty_match_object(Match) of [] -> ok; [Session] -> mnesia:dirty_delete_object(Session) end. send_json(Req, Status, Data) -> Body = jsx:encode(Data), cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req). send_error(Req, Status, Message) -> Body = jsx:encode(#{error => Message}), cowboy_req:reply(Status, #{<<"content-type">> => <<"application/json">>}, Body, Req).