Files
backend/common/Auth.cc
T

67 lines
1.7 KiB
C++

#include "common/Auth.h"
#include "common/Crypto.h"
#include <drogon/drogon.h>
namespace visione::auth
{
std::optional<std::string> 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<UserContext> 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<long long>(),
row["email"].as<std::string>(),
row["role"].as<std::string>()};
}
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