108 lines
3.0 KiB
C++
108 lines
3.0 KiB
C++
#include <sodium.h>
|
|
#include "login.hpp"
|
|
#include "crow/http_response.h"
|
|
#include "databasepool.h"
|
|
#include "utils.hpp"
|
|
#include "SessionHandler.hpp"
|
|
namespace login
|
|
{
|
|
|
|
SessionHandler sessionHandler;
|
|
|
|
std::string hashPassword(const std::string& password)
|
|
{
|
|
// Allocate storage for the hash
|
|
char hash[crypto_pwhash_STRBYTES];
|
|
|
|
// Hash the password using Argon2id
|
|
if (crypto_pwhash_str(
|
|
hash,
|
|
password.c_str(),
|
|
password.size(),
|
|
crypto_pwhash_OPSLIMIT_INTERACTIVE,
|
|
crypto_pwhash_MEMLIMIT_INTERACTIVE
|
|
) != 0) {
|
|
CROW_LOG_ERROR << "Out of memory while hashing password!";
|
|
return "";
|
|
}
|
|
return hash;
|
|
}
|
|
|
|
bool verifyHashWithPassword(const std::string& hash, std::string const& password)
|
|
{
|
|
return crypto_pwhash_str_verify(hash.c_str(), password.c_str(), password.size()) == 0;
|
|
}
|
|
|
|
std::string getSessionId(const crow::request& req) {
|
|
auto cookie_header = req.get_header_value("Cookie");
|
|
std::string prefix = "session_id=";
|
|
auto pos = cookie_header.find(prefix);
|
|
if (pos == std::string::npos) return "";
|
|
return cookie_header.substr(pos + prefix.size(), 32);
|
|
}
|
|
|
|
bool isLoggedIn(const crow::request& req) {
|
|
std::string sessionId = getSessionId(req);
|
|
if (sessionId.empty())
|
|
return false;
|
|
auto userId = sessionHandler.isSessionValid(sessionId);
|
|
return userId.has_value();
|
|
}
|
|
|
|
std::optional<std::string> loginUser(const std::string& username, const std::string& password)
|
|
{
|
|
auto user = getUser(username);
|
|
if (user.has_value()) {
|
|
if (verifyHashWithPassword(user.value().password_hash, password))
|
|
{
|
|
return sessionHandler.createSession(user.value().id);
|
|
}
|
|
}
|
|
return {};
|
|
}
|
|
|
|
bool initLogin(crow::SimpleApp& app)
|
|
{
|
|
if (sodium_init() < 0) {
|
|
CROW_LOG_ERROR << "Failed to Init Sodium";
|
|
return false;
|
|
}
|
|
|
|
// createUser("lukas", "Trollar4928");
|
|
|
|
CROW_ROUTE(app, "/login").methods("POST"_method)
|
|
([](const crow::request& req) {
|
|
auto body = utils::parseBody(req.body);
|
|
if (!body.empty())
|
|
return crow::response(400, "Invalid JSON");
|
|
|
|
auto usenameIt = body.find("username");
|
|
auto passwordIt = body.find("password");
|
|
if(usenameIt == body.end() || passwordIt == body.end())
|
|
return crow::response(400, "No username or password in body");
|
|
|
|
const std::string& username = usenameIt->second;
|
|
const std::string& password = passwordIt->second;
|
|
|
|
// Validate credentials
|
|
auto sessionId = loginUser(username, password);
|
|
if(!sessionId.has_value())
|
|
return crow::response(401, "Invalid credentials");
|
|
|
|
// Set cookie
|
|
crow::response res;
|
|
res.code = 200;
|
|
res.set_header(
|
|
"Set-Cookie",
|
|
"session_id=" + sessionId.value() +
|
|
"; HttpOnly; Path=/; SameSite=Strict"
|
|
// add "; Secure" when using HTTPS
|
|
);
|
|
|
|
res.body = "Logged in";
|
|
return res;
|
|
});
|
|
|
|
return true;
|
|
}
|
|
} |