#include "session.hpp" #include // 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'; }