blob: 706f6f423ab63cbaf001ddbb65c80a8e16ad2076 [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 persistent_data {
class Middleware {
// todo(ed) should read this from a fixed location somewhere, not CWD
static constexpr const char* filename = "bmcweb_persistent_data.json";
int jsonRevision = 1;
public:
struct Context {};
Middleware() { readData(); }
~Middleware() {
if (persistent_data::SessionStore::getInstance().needsWrite()) {
writeData();
}
}
void beforeHandle(crow::Request& req, Response& res, Context& ctx) {}
void afterHandle(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 readData() {
std::ifstream persistentFile(filename);
int fileRevision = 0;
if (persistentFile.is_open()) {
// call with exceptions disabled
auto data = nlohmann::json::parse(persistentFile, nullptr, false);
if (data.is_discarded()) {
BMCWEB_LOG_ERROR << "Error parsing persistent data in json file.";
} else {
for (const auto& item : data.items()) {
if (item.key() == "revision") {
fileRevision = 0;
const uint64_t* uintPtr = item.value().get_ptr<const uint64_t*>();
if (uintPtr == nullptr) {
BMCWEB_LOG_ERROR << "Failed to read revision flag";
} else {
fileRevision = *uintPtr;
}
} else if (item.key() == "system_uuid") {
const std::string* jSystemUuid =
item.value().get_ptr<const std::string*>();
if (jSystemUuid != nullptr) {
systemUuid = *jSystemUuid;
}
} else if (item.key() == "sessions") {
for (const auto& elem : item.value()) {
std::shared_ptr<UserSession> newSession =
UserSession::fromJson(elem);
if (newSession == nullptr) {
BMCWEB_LOG_ERROR
<< "Problem reading session from persistent store";
continue;
}
BMCWEB_LOG_DEBUG << "Restored session: " << newSession->csrfToken
<< " " << newSession->uniqueId << " "
<< newSession->sessionToken;
SessionStore::getInstance().authTokens.emplace(
newSession->sessionToken, 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 needWrite = false;
if (systemUuid.empty()) {
systemUuid = boost::uuids::to_string(boost::uuids::random_generator()());
needWrite = true;
}
if (fileRevision < jsonRevision) {
needWrite = true;
}
// write revision changes or system uuid changes immediately
if (needWrite) {
writeData();
}
}
void writeData() {
std::ofstream persistentFile(filename);
nlohmann::json data{{"sessions", SessionStore::getInstance().authTokens},
{"system_uuid", systemUuid},
{"revision", jsonRevision}};
persistentFile << data;
}
std::string systemUuid{""};
};
} // namespace persistent_data
} // namespace crow