фича: автообновление сессии

This commit is contained in:
2025-01-17 19:09:44 +03:00
parent a4214fd007
commit 3537965393
16 changed files with 170 additions and 96 deletions

View File

@@ -1,8 +1,15 @@
#include "jwt.h"
#include <random>
#include "utils.h"
#include <sys/time.h>
static int64_t milliseconds() {
timeval tv{};
gettimeofday(&tv,nullptr);
return ((tv.tv_sec * 1000000l) + tv.tv_usec) / 1000;
}
std::string http::auth::jwt::secretKey;
void http::auth::jwt::generateSecretKey() {
@@ -16,37 +23,45 @@ void http::auth::jwt::generateSecretKey() {
}
}
// payload, signature
static std::pair<std::string, std::string> parseJwtFromCookie(const std::string& input) {
std::string val1, val2;
size_t dotPos = input.find('.');
// Если точка найдена
if (dotPos != std::string::npos) {
val1 = input.substr(0, dotPos);
// Если в val1 есть еще точки, нужно найти последнюю точку
size_t lastDotPos = val1.find_last_of('.');
if (lastDotPos != std::string::npos) {
val1 = val1.substr(0, lastDotPos + 1);
}
val2 = input.substr(dotPos + 1);
} else {
// Точка не найдена, val1 - вся строка
val1 = input;
}
return std::make_pair(http::utils::b64Decode(val1), val2);
}
http::auth::jwt::Jwt http::auth::jwt::Jwt::fromCookies(const std::string &cookie) {
auto pc = utils::parseCookies(cookie);
Jwt t;
if (pc.find("auth") != pc.end()) {
auto tmp = parseJwtFromCookie(pc.at("auth"));
t.payload = tmp.first;
t.signature = tmp.second;
const auto auth = pc.at("auth");
int firstDot = -1;
int secondDot = -1;
for (size_t i = 0; i < auth.size(); i++) {
if (auth[i] == '.') {
if (firstDot < 0) { firstDot = static_cast<int>(i); }
else if (secondDot < 0) { secondDot = static_cast<int>(i); }
else {
// так быть не должно
return t;
}
}
}
if (firstDot < 0 || secondDot < 0 || secondDot - firstDot == 0) {
// так тоже быть не должно
return t;
}
try {
t.payload = auth.substr(0, firstDot);
t.signature = auth.substr(secondDot + 1);
t.lastUpdate = std::stol(auth.substr(firstDot + 1, secondDot - firstDot - 1));
// теперь проверим, что сигнатура верная, только тогда декодируем строку юзера
auto realSignature = utils::sha256(t.payload + std::to_string(t.lastUpdate) + secretKey);
if (t.signature != realSignature) {
t.payload.clear();
} else {
t.payload = utils::b64Decode(t.payload);
}
} catch (std::exception& e) {
t.payload.clear();
t.lastUpdate = 0;
t.signature.clear();
}
}
return t;
@@ -55,6 +70,7 @@ http::auth::jwt::Jwt http::auth::jwt::Jwt::fromCookies(const std::string &cookie
http::auth::jwt::Jwt http::auth::jwt::Jwt::fromUser(const std::string &user) {
Jwt t;
t.payload = user;
t.lastUpdate = milliseconds();
return t;
}
@@ -63,18 +79,40 @@ bool http::auth::jwt::Jwt::isValid() {
return false;
}
auto realSignature = utils::sha256(this->payload + secretKey);
return signature == realSignature;
// проверка сигнатуры не нужна, она была на стадии парсинга куки
// auto realSignature = utils::sha256(utils::b64Encode(this->payload) + std::to_string(this->lastUpdate) + secretKey);
// if (signature != realSignature) {
// return false;
// }
const auto currTime = milliseconds();
return currTime <= lastUpdate + SESSION_LIVE_MS && currTime >= lastUpdate;
}
std::string http::auth::jwt::Jwt::getUsername() {
return payload;
}
std::string http::auth::jwt::Jwt::asCookie() {
signature = utils::sha256(this->payload + secretKey);
auto val = utils::b64Encode(payload) + "." + signature;
return "auth=" + val + ";Path=/; Max-Age=86400; HttpOnly; SameSite=Lax";
std::string http::auth::jwt::Jwt::asCookie(bool isSecure) {
this->lastUpdate = milliseconds();
const auto uTime = std::to_string(this->lastUpdate);
const auto encodedPayload = utils::b64Encode(payload);
signature = utils::sha256(encodedPayload + uTime + secretKey);
const auto val = encodedPayload + "." + uTime + "." + signature;
std::string cookie = "auth=";
cookie += val;
cookie += ";Path=/; Max-Age=";
cookie += std::to_string(SESSION_LIVE_MS / 1000);
if (isSecure) {
cookie += "; Secure";
}
cookie += "; HttpOnly; SameSite=Lax";
return cookie;
}
bool http::auth::jwt::Jwt::needUpdate() const {
return milliseconds() >= lastUpdate + SESSION_UPDATE_THRESHOLD;
}
http::auth::jwt::Jwt::~Jwt() = default;