blob: 334a84de930f64493d72a074fe98b366d4f42863 [file] [log] [blame]
Ed Tanousba9f9a62017-10-11 16:40:35 -07001#pragma once
2
Ed Tanousba9f9a62017-10-11 16:40:35 -07003#include <nlohmann/json.hpp>
4#include <pam_authenticate.hpp>
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +02005#include <sessions.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -07006#include <webassets.hpp>
Borawski.Lukasz16238972018-01-17 15:36:53 +01007#include <random>
Ed Tanousba9f9a62017-10-11 16:40:35 -07008#include <crow/app.h>
9#include <crow/http_request.h>
10#include <crow/http_response.h>
11#include <boost/container/flat_map.hpp>
12#include <boost/uuid/uuid.hpp>
13#include <boost/uuid/uuid_generators.hpp>
14#include <boost/uuid/uuid_io.hpp>
15
16namespace crow {
17
18namespace PersistentData {
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010019
Ed Tanousc963aa42017-10-27 16:00:19 -070020class Middleware {
21 // todo(ed) should read this from a fixed location somewhere, not CWD
22 static constexpr const char* filename = "bmcweb_persistent_data.json";
23 int json_revision = 1;
24
25 public:
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010026 struct context {};
Ed Tanousc963aa42017-10-27 16:00:19 -070027
28 Middleware() { read_data(); }
29
30 ~Middleware() {
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +020031 if (PersistentData::SessionStore::getInstance().needs_write()) {
Ed Tanousc963aa42017-10-27 16:00:19 -070032 write_data();
33 }
34 }
35
Kowalski, Kamil2b7981f2018-01-31 13:24:59 +010036 void before_handle(crow::request& req, response& res, context& ctx) {}
Ed Tanousc963aa42017-10-27 16:00:19 -070037
38 void after_handle(request& req, response& res, context& ctx) {}
39
40 // TODO(ed) this should really use protobuf, or some other serialization
41 // library, but adding another dependency is somewhat outside the scope of
42 // this application for the moment
43 void read_data() {
44 std::ifstream persistent_file(filename);
45 int file_revision = 0;
46 if (persistent_file.is_open()) {
47 // call with exceptions disabled
48 auto data = nlohmann::json::parse(persistent_file, nullptr, false);
Ed Tanouse1ae5332018-07-09 15:21:27 -070049 if (data.is_discarded()) {
50 CROW_LOG_ERROR << "Error parsing persistent data in json file.";
51 } else {
52 for (const auto& item : data.items()) {
53 if (item.key() == "revision") {
54 file_revision = 0;
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010055
Ed Tanouse1ae5332018-07-09 15:21:27 -070056 const uint64_t* uintPtr = item.value().get_ptr<const uint64_t*>();
57 if (uintPtr == nullptr) {
58 CROW_LOG_ERROR << "Failed to read revision flag";
59 } else {
60 file_revision = *uintPtr;
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010061 }
Ed Tanouse1ae5332018-07-09 15:21:27 -070062 } else if (item.key() == "system_uuid") {
63 const std::string* jSystemUuid =
64 item.value().get_ptr<const std::string*>();
65 if (jSystemUuid != nullptr) {
66 system_uuid = *jSystemUuid;
67 }
68 } else if (item.key() == "sessions") {
69 for (const auto& elem : item.value()) {
70 std::shared_ptr<UserSession> newSession =
71 UserSession::fromJson(elem);
72
73 if (newSession == nullptr) {
74 CROW_LOG_ERROR
75 << "Problem reading session from persistent store";
76 continue;
77 }
78
79 CROW_LOG_DEBUG << "Restored session: " << newSession->csrf_token
80 << " " << newSession->unique_id << " "
81 << newSession->session_token;
82 SessionStore::getInstance().auth_tokens.emplace(
83 newSession->session_token, newSession);
84 }
85 } else {
86 // Do nothing in the case of extra fields. We may have cases where
87 // fields are added in the future, and we want to at least attempt
88 // to gracefully support downgrades in that case, even if we don't
89 // officially support it
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010090 }
91 }
Ed Tanousc963aa42017-10-27 16:00:19 -070092 }
93 }
94 bool need_write = false;
95
96 if (system_uuid.empty()) {
97 system_uuid = boost::uuids::to_string(boost::uuids::random_generator()());
98 need_write = true;
99 }
100 if (file_revision < json_revision) {
101 need_write = true;
102 }
103 // write revision changes or system uuid changes immediately
104 if (need_write) {
105 write_data();
106 }
107 }
108
109 void write_data() {
110 std::ofstream persistent_file(filename);
Ed Tanouse1ae5332018-07-09 15:21:27 -0700111 nlohmann::json data{
112 {"sessions", PersistentData::SessionStore::getInstance().auth_tokens},
113 {"system_uuid", system_uuid},
114 {"revision", json_revision}};
Ed Tanousc963aa42017-10-27 16:00:19 -0700115 persistent_file << data;
116 }
117
Ed Tanouse1ae5332018-07-09 15:21:27 -0700118 std::string system_uuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700119};
120
Borawski.Lukasz4b1b8682018-04-04 12:50:16 +0200121} // namespace PersistentData
Ed Tanousba9f9a62017-10-11 16:40:35 -0700122} // namespace crow