blob: b384f0230401fe73157a6e591c47339ffcbbd7d0 [file] [log] [blame]
Ed Tanousba9f9a62017-10-11 16:40:35 -07001#pragma once
2
Ed Tanousba9f9a62017-10-11 16:40:35 -07003#include <crow/app.h>
4#include <crow/http_request.h>
5#include <crow/http_response.h>
Ed Tanous1abe55e2018-09-05 08:30:59 -07006
Ed Tanousba9f9a62017-10-11 16:40:35 -07007#include <boost/container/flat_map.hpp>
8#include <boost/uuid/uuid.hpp>
9#include <boost/uuid/uuid_generators.hpp>
10#include <boost/uuid/uuid_io.hpp>
Ed Tanous1abe55e2018-09-05 08:30:59 -070011#include <nlohmann/json.hpp>
12#include <pam_authenticate.hpp>
13#include <random>
14#include <sessions.hpp>
15#include <webassets.hpp>
Ed Tanousba9f9a62017-10-11 16:40:35 -070016
Ed Tanous1abe55e2018-09-05 08:30:59 -070017namespace crow
18{
Ed Tanousba9f9a62017-10-11 16:40:35 -070019
Ed Tanous1abe55e2018-09-05 08:30:59 -070020namespace persistent_data
21{
Borawski.Lukasz9d8fd302018-01-05 14:56:09 +010022
Ed Tanous1abe55e2018-09-05 08:30:59 -070023class Middleware
24{
25 // todo(ed) should read this from a fixed location somewhere, not CWD
26 static constexpr const char* filename = "bmcweb_persistent_data.json";
Ed Tanousb01bf292019-03-25 19:25:26 +000027 int jsonRevision = 1;
Ed Tanousc963aa42017-10-27 16:00:19 -070028
Ed Tanous1abe55e2018-09-05 08:30:59 -070029 public:
30 struct Context
31 {
32 };
Ed Tanousc963aa42017-10-27 16:00:19 -070033
Ed Tanous1abe55e2018-09-05 08:30:59 -070034 Middleware()
35 {
36 readData();
Ed Tanousc963aa42017-10-27 16:00:19 -070037 }
Ed Tanousc963aa42017-10-27 16:00:19 -070038
Ed Tanous1abe55e2018-09-05 08:30:59 -070039 ~Middleware()
40 {
41 if (persistent_data::SessionStore::getInstance().needsWrite())
42 {
43 writeData();
Kowalski, Kamil5cef0f72018-02-15 15:26:51 +010044 }
Ed Tanousc963aa42017-10-27 16:00:19 -070045 }
Ed Tanousc963aa42017-10-27 16:00:19 -070046
Ed Tanous1abe55e2018-09-05 08:30:59 -070047 void beforeHandle(crow::Request& req, Response& res, Context& ctx)
48 {
Ed Tanousc963aa42017-10-27 16:00:19 -070049 }
Ed Tanousc963aa42017-10-27 16:00:19 -070050
Ed Tanous1abe55e2018-09-05 08:30:59 -070051 void afterHandle(Request& req, Response& res, Context& ctx)
52 {
53 }
Ed Tanousc963aa42017-10-27 16:00:19 -070054
Ed Tanous1abe55e2018-09-05 08:30:59 -070055 // TODO(ed) this should really use protobuf, or some other serialization
56 // library, but adding another dependency is somewhat outside the scope of
57 // this application for the moment
58 void readData()
59 {
60 std::ifstream persistentFile(filename);
Ed Tanousb01bf292019-03-25 19:25:26 +000061 int fileRevision = 0;
Ed Tanous1abe55e2018-09-05 08:30:59 -070062 if (persistentFile.is_open())
63 {
64 // call with exceptions disabled
65 auto data = nlohmann::json::parse(persistentFile, nullptr, false);
66 if (data.is_discarded())
67 {
68 BMCWEB_LOG_ERROR
69 << "Error parsing persistent data in json file.";
70 }
71 else
72 {
73 for (const auto& item : data.items())
74 {
75 if (item.key() == "revision")
76 {
77 fileRevision = 0;
78
79 const uint64_t* uintPtr =
80 item.value().get_ptr<const uint64_t*>();
81 if (uintPtr == nullptr)
82 {
83 BMCWEB_LOG_ERROR << "Failed to read revision flag";
84 }
85 else
86 {
87 fileRevision = *uintPtr;
88 }
89 }
90 else if (item.key() == "system_uuid")
91 {
92 const std::string* jSystemUuid =
93 item.value().get_ptr<const std::string*>();
94 if (jSystemUuid != nullptr)
95 {
96 systemUuid = *jSystemUuid;
97 }
98 }
99 else if (item.key() == "sessions")
100 {
101 for (const auto& elem : item.value())
102 {
103 std::shared_ptr<UserSession> newSession =
104 UserSession::fromJson(elem);
105
106 if (newSession == nullptr)
107 {
108 BMCWEB_LOG_ERROR << "Problem reading session "
109 "from persistent store";
110 continue;
111 }
112
113 BMCWEB_LOG_DEBUG
114 << "Restored session: " << newSession->csrfToken
115 << " " << newSession->uniqueId << " "
116 << newSession->sessionToken;
117 SessionStore::getInstance().authTokens.emplace(
118 newSession->sessionToken, newSession);
119 }
120 }
121 else
122 {
123 // Do nothing in the case of extra fields. We may have
124 // cases where fields are added in the future, and we
125 // want to at least attempt to gracefully support
126 // downgrades in that case, even if we don't officially
127 // support it
128 }
129 }
130 }
131 }
132 bool needWrite = false;
133
134 if (systemUuid.empty())
135 {
136 systemUuid =
137 boost::uuids::to_string(boost::uuids::random_generator()());
138 needWrite = true;
139 }
140 if (fileRevision < jsonRevision)
141 {
142 needWrite = true;
143 }
144 // write revision changes or system uuid changes immediately
145 if (needWrite)
146 {
147 writeData();
148 }
149 }
150
151 void writeData()
152 {
153 std::ofstream persistentFile(filename);
154 nlohmann::json data{
155 {"sessions", SessionStore::getInstance().authTokens},
156 {"system_uuid", systemUuid},
157 {"revision", jsonRevision}};
158 persistentFile << data;
159 }
160
161 std::string systemUuid{""};
Ed Tanousba9f9a62017-10-11 16:40:35 -0700162};
163
Ed Tanous1abe55e2018-09-05 08:30:59 -0700164} // namespace persistent_data
165} // namespace crow