From 45f506a0877d14f13de26d8c8724b59cd0a2e9cb Mon Sep 17 00:00:00 2001 From: ANTON IGNATEV Date: Mon, 4 May 2026 21:08:56 +0300 Subject: [PATCH] Add some functionality new handler for me --- auth.db | Bin 40960 -> 40960 bytes src/application/application.cpp | 10 +++- src/http/controllers/auth_controller.cpp | 48 +++++++++++++++--- src/http/controllers/auth_controller.hpp | 5 +- src/security/session_token_service.cpp | 4 ++ src/security/session_token_service.hpp | 2 + src/service/auth_service.cpp | 36 ++++++++++++- .../{auto_service.hpp => auth_service.hpp} | 7 +++ 8 files changed, 102 insertions(+), 10 deletions(-) rename src/service/{auto_service.hpp => auth_service.hpp} (86%) diff --git a/auth.db b/auth.db index d2eee244d7ee9f4a8b63e726e67138f1581de6cb..d9818a263fbb2a5dc15c967bcb721df364af60d8 100644 GIT binary patch delta 588 zcmbu6FHFNg6vkUdTLkSJC_)ez<{uv08G+hINk79969q}1`Su`E@olo(I0K#*Oh6`SZ0_-+{BrrT5D@;BB{YFmP%nm zC5u%WGfHEtNg^^~7)l7@LK&}V-Ty)fs+1DkpVwTT-P5mPhTHv}VJm-a`Y>|f3qIik#_$HC za^PoJ^ct?~1=Z^h#}{j*t>?fyyuck?!Wr~R+aU}uufmO)a|A05>ed{m9~CpdbY|Z% C)R^c1 delta 123 zcmZoTz|?SnX~TbgM%K-Y2LJgt|F>sV;9=o2Vc_rOm*QK_XR=vPK!tC!N!|rU4i>%_ z4E%chC7T5beE23#n851F(#Xp=**?! &&callback) { + auth_controller.me(req, std::move(callback)); + }, + { drogon::Get }); + drogon::app().registerHandler( "/login", [&auth_controller](const drogon::HttpRequestPtr &req, diff --git a/src/http/controllers/auth_controller.cpp b/src/http/controllers/auth_controller.cpp index ff1a9cb..f3e578c 100644 --- a/src/http/controllers/auth_controller.cpp +++ b/src/http/controllers/auth_controller.cpp @@ -1,13 +1,47 @@ #include "http/controllers/auth_controller.hpp" #include "service/auth_errors.hpp" -#include "service/auto_service.hpp" +#include "service/auth_service.hpp" #include #include AuthController::AuthController(AuthService &auth_service) - : auto_servise_(auth_service) {} + : auth_servise_(auth_service) {} + +void AuthController::me(const drogon::HttpRequestPtr &req, + std::function &&callback) const { + const auto session_token = req->getCookie("sid"); + + try { + const auto user = auth_servise_.authenticate_by_session_token(session_token); + + Json::Value body; + body["id"] = static_cast(user.id); + body["email"] = user.email; + + auto response = drogon::HttpResponse::newHttpJsonResponse(body); + response->setStatusCode(drogon::k200OK); + callback(response); + } catch(const UnauthorizedError &ex) { + Json::Value error; + error["error"]["code"] = "unauthorized"; + error["error"]["message"] = ex.what(); + + auto response = drogon::HttpResponse::newHttpJsonResponse(error); + response->setStatusCode(drogon::k401Unauthorized); + callback(response); + } catch(const std::exception &e) { + Json::Value error; + error["error"]["code"] = "internal_error"; + error["error"]["message"] = "Internal server error"; + + auto response = drogon::HttpResponse::newHttpJsonResponse(error); + response->setStatusCode(drogon::k500InternalServerError); + callback(response); + ; + } +} void AuthController::login(const drogon::HttpRequestPtr &req, std::function &&callback) const { @@ -17,13 +51,13 @@ void AuthController::login(const drogon::HttpRequestPtr error["error"]["code"] = "invalid_request"; error["error"]["message"] = "Expected JSON body with email and password"; - auto responce = drogon::HttpResponse::newHttpJsonResponse(error); - responce->setStatusCode(drogon::k400BadRequest); - callback(responce); + auto response = drogon::HttpResponse::newHttpJsonResponse(error); + response->setStatusCode(drogon::k400BadRequest); + callback(response); return; } try { - const auto result = auto_servise_.login(LoginCommand{ + const auto result = auth_servise_.login(LoginCommand{ .email = (*json)["email"].asString(), .password = (*json)["password"].asString(), }); @@ -91,7 +125,7 @@ void AuthController::register_user( } try { - const auto result = auto_servise_.register_user(RegisterCommand{ + const auto result = auth_servise_.register_user(RegisterCommand{ .email = (*json)["email"].asString(), .password = (*json)["password"].asString(), }); diff --git a/src/http/controllers/auth_controller.hpp b/src/http/controllers/auth_controller.hpp index 8f7b185..9cd1a86 100644 --- a/src/http/controllers/auth_controller.hpp +++ b/src/http/controllers/auth_controller.hpp @@ -15,10 +15,13 @@ public: void login(const drogon::HttpRequestPtr &req, std::function &&callback) const; + void me(const drogon::HttpRequestPtr &req, + std::function &&callback) const; + private: bool isValidAuthJson(const std::shared_ptr &req) const; bool isValidLoginJson(const std::shared_ptr &req) const; private: - AuthService &auto_servise_; + AuthService &auth_servise_; }; \ No newline at end of file diff --git a/src/security/session_token_service.cpp b/src/security/session_token_service.cpp index a8e899e..a98ec15 100644 --- a/src/security/session_token_service.cpp +++ b/src/security/session_token_service.cpp @@ -26,6 +26,10 @@ SessionTokenPair SessionTokenService::generate() const { return SessionTokenPair{ .raw_token = raw_token, .token_hash = token_hash }; } +std::string SessionTokenService::hash_token(std::string_view raw_token) const { + return sha256_hex(std::string{ raw_token }); +} + std::string SessionTokenService::generate_random_token() { unsigned char buffer[kTokenSizeBytes]; if(RAND_bytes(buffer, sizeof(buffer)) != 1) { diff --git a/src/security/session_token_service.hpp b/src/security/session_token_service.hpp index 84c76d1..db73a69 100644 --- a/src/security/session_token_service.hpp +++ b/src/security/session_token_service.hpp @@ -9,6 +9,8 @@ class SessionTokenService { public: SessionTokenPair generate() const; + std::string hash_token(std::string_view raw_token) const; + private: static std::string generate_random_token(); static std::string sha256_hex(const std::string &input); diff --git a/src/service/auth_service.cpp b/src/service/auth_service.cpp index 488d81a..3568e8d 100644 --- a/src/service/auth_service.cpp +++ b/src/service/auth_service.cpp @@ -6,7 +6,7 @@ #include "util/time_utils.hpp" #include "util/validation.hpp" -#include +#include #include AuthService::AuthService(UserRepository &users, SessionRepository &session, @@ -32,6 +32,40 @@ void AuthService::validateData(std::string_view email, std::string_view password throw EmailAlreadyExistsError("Email already exists"); } } + +CurrentUserResult AuthService::authenticate_by_session_token(std::string_view raw_token) const { + if(raw_token.empty()) { + throw UnauthorizedError("Unauthorized"); + } + + const auto token_hash = token_service_.hash_token(raw_token); + + const auto session = sessions_.find_by_token_hash(token_hash); + + if(!session.has_value()) { + throw UnauthorizedError("Unauthorized"); + } + + if(session->revoked_at.has_value()) { + throw UnauthorizedError("Unauthorized"); + } + + const auto now = now_utc_iso8601(); + if(session->expires_at <= now) { + throw UnauthorizedError("Session expired"); + } + + const auto user = users_.find_by_id(session->user_id); + if(!user.has_value() || !user->is_active) { + throw UnauthorizedError("Unauthorized"); + } + + return CurrentUserResult{ + .id = user->id, + .email = user->email, + }; +} + LoginResult AuthService::login(const LoginCommand &command) const { const auto email = normalize_email(command.email); // validateData(email, command.password); diff --git a/src/service/auto_service.hpp b/src/service/auth_service.hpp similarity index 86% rename from src/service/auto_service.hpp rename to src/service/auth_service.hpp index 6973d30..34f6025 100644 --- a/src/service/auto_service.hpp +++ b/src/service/auth_service.hpp @@ -27,6 +27,11 @@ struct RegisterResult { std::string email; }; +struct CurrentUserResult { + std::int64_t id{}; + std::string email; +}; + class AuthService { public: AuthService(UserRepository &users, SessionRepository &session, PasswordHasher &password_hasher, @@ -35,6 +40,8 @@ public: RegisterResult register_user(const RegisterCommand &command) const; LoginResult login(const LoginCommand &loginCommand) const; + CurrentUserResult authenticate_by_session_token(std::string_view raw_token) const; + private: void validateData(std::string_view email, std::string_view password) const;