blob: 334a84de930f64493d72a074fe98b366d4f42863 [file] [log] [blame]
#pragma once
#include <nlohmann/json.hpp>
#include <pam_authenticate.hpp>
#include <sessions.hpp>
#include <webassets.hpp>
#include <random>
#include <crow/app.h>
#include <crow/http_request.h>
#include <crow/http_response.h>
#include <boost/container/flat_map.hpp>
#include <boost/uuid/uuid.hpp>
#include <boost/uuid/uuid_generators.hpp>
#include <boost/uuid/uuid_io.hpp>
namespace crow {
namespace PersistentData {
class Middleware {
// todo(ed) should read this from a fixed location somewhere, not CWD
static constexpr const char* filename = "bmcweb_persistent_data.json";
int json_revision = 1;
public:
struct context {};
Middleware() { read_data(); }
~Middleware() {
if (PersistentData::SessionStore::getInstance().needs_write()) {
write_data();
}
}
void before_handle(crow::request& req, response& res, context& ctx) {}
void after_handle(request& req, response& res, context& ctx) {}
// TODO(ed) this should really use protobuf, or some other serialization
// library, but adding another dependency is somewhat outside the scope of
// this application for the moment
void read_data() {
std::ifstream persistent_file(filename);
int file_revision = 0;
if (persistent_file.is_open()) {
// call with exceptions disabled
auto data = nlohmann::json::parse(persistent_file, nullptr, false);
if (data.is_discarded()) {
CROW_LOG_ERROR << "Error parsing persistent data in json file.";
} else {
for (const auto& item : data.items()) {
if (item.key() == "revision") {
file_revision = 0;
const uint64_t* uintPtr = item.value().get_ptr<const uint64_t*>();
if (uintPtr == nullptr) {
CROW_LOG_ERROR << "Failed to read revision flag";
} else {
file_revision = *uintPtr;
}
} else if (item.key() == "system_uuid") {
const std::string* jSystemUuid =
item.value().get_ptr<const std::string*>();
if (jSystemUuid != nullptr) {
system_uuid = *jSystemUuid;
}
} else if (item.key() == "sessions") {
for (const auto& elem : item.value()) {
std::shared_ptr<UserSession> newSession =
UserSession::fromJson(elem);
if (newSession == nullptr) {
CROW_LOG_ERROR
<< "Problem reading session from persistent store";
continue;
}
CROW_LOG_DEBUG << "Restored session: " << newSession->csrf_token
<< " " << newSession->unique_id << " "
<< newSession->session_token;
SessionStore::getInstance().auth_tokens.emplace(
newSession->session_token, newSession);
}
} else {
// Do nothing in the case of extra fields. We may have cases where
// fields are added in the future, and we want to at least attempt
// to gracefully support downgrades in that case, even if we don't
// officially support it
}
}
}
}
bool need_write = false;
if (system_uuid.empty()) {
system_uuid = boost::uuids::to_string(boost::uuids::random_generator()());
need_write = true;
}
if (file_revision < json_revision) {
need_write = true;
}
// write revision changes or system uuid changes immediately
if (need_write) {
write_data();
}
}
void write_data() {
std::ofstream persistent_file(filename);
nlohmann::json data{
{"sessions", PersistentData::SessionStore::getInstance().auth_tokens},
{"system_uuid", system_uuid},
{"revision", json_revision}};
persistent_file << data;
}
std::string system_uuid{""};
};
} // namespace PersistentData
} // namespace crow