108 lines
3.7 KiB
C++
108 lines
3.7 KiB
C++
#include "session.hpp"
|
|
#include <pgmspace.h> // Required for PROGMEM
|
|
|
|
// Definition of the global instance
|
|
SessionManager sessionManager;
|
|
|
|
// The character set is now stored in flash memory to save RAM.
|
|
const char charset[] PROGMEM = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
|
|
|
|
SessionManager::SessionManager() {
|
|
session_mutex_ = xSemaphoreCreateMutex();
|
|
for (size_t i = 0; i < MAX_SESSIONS; ++i) {
|
|
sessions_[i].username[0] = '\0';
|
|
}
|
|
}
|
|
|
|
SessionManager::~SessionManager() {
|
|
vSemaphoreDelete(session_mutex_);
|
|
}
|
|
|
|
const char* SessionManager::createSession(const char* username) {
|
|
const char* result_token = nullptr;
|
|
// Lock the mutex to ensure exclusive access to the sessions array.
|
|
if (xSemaphoreTake(session_mutex_, portMAX_DELAY) == pdTRUE) {
|
|
for (size_t i = 0; i < MAX_SESSIONS; ++i) {
|
|
if (sessions_[i].username[0] == '\0') {
|
|
strncpy(sessions_[i].username, username, sizeof(sessions_[i].username) - 1);
|
|
sessions_[i].username[sizeof(sessions_[i].username) - 1] = '\0';
|
|
|
|
generateToken(sessions_[i].token, sizeof(sessions_[i].token));
|
|
|
|
sessions_[i].expiry_time = millis() + (15 * 60 * 1000);
|
|
|
|
result_token = sessions_[i].token;
|
|
break; // Exit loop once a slot is found
|
|
}
|
|
}
|
|
xSemaphoreGive(session_mutex_); // Release the mutex
|
|
}
|
|
return result_token;
|
|
}
|
|
|
|
const char* SessionManager::validateSession(const char* token) {
|
|
if (token == nullptr) {
|
|
return nullptr;
|
|
}
|
|
|
|
// We must copy the username to a static buffer, because the session array
|
|
// could be modified by another task after we release the mutex.
|
|
static char valid_username[33];
|
|
valid_username[0] = '\0';
|
|
|
|
if (xSemaphoreTake(session_mutex_, portMAX_DELAY) == pdTRUE) {
|
|
for (size_t i = 0; i < MAX_SESSIONS; ++i) {
|
|
if (sessions_[i].username[0] != '\0' && strcmp(sessions_[i].token, token) == 0) {
|
|
if (millis() < sessions_[i].expiry_time) {
|
|
strcpy(valid_username, sessions_[i].username);
|
|
} else {
|
|
sessions_[i].username[0] = '\0'; // Expired, clear it
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
xSemaphoreGive(session_mutex_);
|
|
}
|
|
|
|
return (valid_username[0] != '\0') ? valid_username : nullptr;
|
|
}
|
|
|
|
bool SessionManager::endSession(const char* token) {
|
|
if (token == nullptr) return false;
|
|
|
|
bool found = false;
|
|
if (xSemaphoreTake(session_mutex_, portMAX_DELAY) == pdTRUE) {
|
|
for (size_t i = 0; i < MAX_SESSIONS; ++i) {
|
|
if (sessions_[i].username[0] != '\0' && strcmp(sessions_[i].token, token) == 0) {
|
|
sessions_[i].username[0] = '\0';
|
|
found = true;
|
|
break;
|
|
}
|
|
}
|
|
xSemaphoreGive(session_mutex_);
|
|
}
|
|
return found;
|
|
}
|
|
|
|
void SessionManager::cleanupExpiredSessions() {
|
|
unsigned long current_time = millis();
|
|
if (xSemaphoreTake(session_mutex_, portMAX_DELAY) == pdTRUE) {
|
|
for (size_t i = 0; i < MAX_SESSIONS; ++i) {
|
|
if (sessions_[i].username[0] != '\0') {
|
|
if (current_time >= sessions_[i].expiry_time) {
|
|
sessions_[i].username[0] = '\0';
|
|
}
|
|
}
|
|
}
|
|
xSemaphoreGive(session_mutex_);
|
|
}
|
|
}
|
|
|
|
void SessionManager::generateToken(char* buffer, size_t buffer_size) {
|
|
const size_t charset_size = sizeof(charset) - 1;
|
|
for (size_t i = 0; i < buffer_size - 1; ++i) {
|
|
// Read the character directly from flash memory (PROGMEM).
|
|
buffer[i] = pgm_read_byte(&charset[esp_random() % charset_size]);
|
|
}
|
|
buffer[buffer_size - 1] = '\0';
|
|
} |