#include "common/Auth.h" #include "common/Crypto.h" #include namespace visione::auth { std::optional bearerToken(const drogon::HttpRequestPtr &request) { const auto header = request->getHeader("Authorization"); constexpr std::string_view prefix = "Bearer "; if (!header.starts_with(prefix)) { return std::nullopt; } return header.substr(prefix.size()); } std::optional authenticate(const drogon::HttpRequestPtr &request) { const auto token = bearerToken(request); if (!token) { return std::nullopt; } auto db = drogon::app().getDbClient(); const auto result = db->execSqlSync( "SELECT u.id, u.email, COALESCE(MIN(r.name), 'citizen') AS role " "FROM api_tokens t " "JOIN users u ON u.id = t.user_id " "LEFT JOIN user_roles ur ON ur.user_id = u.id " "LEFT JOIN roles r ON r.id = ur.role_id " "WHERE t.token_hash = ? AND t.revoked_at IS NULL " "AND t.expires_at > NOW() AND u.banned = FALSE " "GROUP BY u.id, u.email", crypto::hashSecret(*token)); if (result.empty()) { return std::nullopt; } const auto &row = result[0]; return UserContext{row["id"].as(), row["email"].as(), row["role"].as()}; } bool hasRole(const UserContext &user, const std::string &role) { return user.role == role; } bool canManageReports(const UserContext &user) { return user.role == "admin" || user.role == "operator"; } bool isAdmin(const UserContext &user) { return user.role == "admin"; } } // namespace visione::auth