-
Notifications
You must be signed in to change notification settings - Fork 9
/
support.hh
165 lines (146 loc) · 5.71 KB
/
support.hh
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
#pragma once
#include <optional>
#include <unordered_map>
#include <unordered_set>
#include <string>
#include <mutex>
#include <vector>
#include "jsonhelper.hh"
#include "nlohmann/json.hpp"
#include "sqlwriter.hh"
#include "fmt/core.h"
#include "httplib.h"
struct LockedSqw
{
LockedSqw(const LockedSqw&) = delete;
SQLiteWriter& sqw;
std::mutex& sqwlock;
auto query(const std::string& query, const std::initializer_list<SQLiteWriter::var_t>& values ={})
{
std::lock_guard<std::mutex> l(sqwlock);
return sqw.queryT(query, values);
}
void queryJ(httplib::Response &res, const std::string& q, const std::initializer_list<SQLiteWriter::var_t>& values={})
{
auto result = query(q, values);
res.set_content(packResultsJsonStr(result), "application/json");
}
auto queryJRet(const std::string& q, const std::initializer_list<SQLiteWriter::var_t>& values={})
{
auto result = query(q, values);
return packResultsJson(result);
}
void addValue(const std::initializer_list<std::pair<const char*, SQLiteWriter::var_t>>& values, const std::string& table="data")
{
std::lock_guard<std::mutex> l(sqwlock);
sqw.addValue(values, table);
}
void addValue(const std::vector<std::pair<const char*, SQLiteWriter::var_t>>& values, const std::string& table="data")
{
std::lock_guard<std::mutex> l(sqwlock);
sqw.addValue(values, table);
}
};
int trifectaMain(int argc, const char* argv[]);
std::unordered_map<std::string, std::string> getCookies(const std::string& cookiestr);
uint64_t getRandom64();
std::string makeShortID(uint64_t id);
std::string getSessionID(const httplib::Request &req);
std::string& testrunnerPw();
void sendAsciiEmailAsync(const std::string& server, const std::string& from, const std::string& to, const std::string& subject, const std::string& textBody);
void replaceSubstring(std::string &originalString, const std::string &searchString, const std::string &replaceString);
std::string htmlEscape(const std::string& str);
enum class Capability {IsUser=1, Admin=2, EmailAuthenticated=3};
struct Users
{
Users(LockedSqw& lsqw) : d_lsqw(lsqw)
{}
bool checkPassword(const std::string& user, const std::string& password) const;
void createUser(const std::string& user, const std::string& password, const std::string& email, bool admin);
void changePassword(const std::string& user, const std::string& password);
std::string getEmail(const std::string& user);
void setEmail(const std::string& user, const std::string& email);
void delUser(const std::string& user);
bool userHasCap(const std::string& user, const Capability& cap, const httplib::Request* req=0);
bool hasPassword(const std::string& user);
bool isUserDisabled(const std::string& user); // user that doesn't exist is also disabled
LockedSqw& d_lsqw;
};
class Sessions
{
public:
Sessions(LockedSqw& lsqw) : d_lsqw(lsqw)
{}
std::string getUserForSession(const std::string& sessionid, const std::string& agent, const std::string& ip) const;
std::string createSessionForUser(const std::string& user, const std::string& agent, const std::string& ip, bool authenticated=false, std::optional<time_t> expire={});
void dropSession(const std::string& sessionid, std::optional<std::string> user={});
std::string getUser(const httplib::Request &req, const std::string& ip) const;
private:
LockedSqw& d_lsqw;
};
struct SimpleWebSystem
{
explicit SimpleWebSystem(LockedSqw& lsqw);
LockedSqw& d_lsqw;
Users d_users;
Sessions d_sessions;
httplib::Server d_svr;
std::unordered_set<std::string> d_tproxies;
std::string d_realipheadername;
std::string d_extraCookieSpec;
std::string getIP(const httplib::Request&) const;
struct ComboReq
{
LockedSqw& lsqw;
const httplib::Request &req;
httplib::Response &res;
Users& users;
Sessions& sessions;
const SimpleWebSystem& sws;
std::string user;
std::string getIP()
{
return sws.getIP(req);
}
void log(const std::initializer_list<std::pair<const char*, SQLiteWriter::var_t>>& fields)
{
// add agent?
std::vector<std::pair<const char*, SQLiteWriter::var_t>> values{{"user", user}, {"ip", getIP()}, {"tstamp", time(0)}};
for(const auto& f : fields)
values.push_back(f);
lsqw.addValue(values, "log");
}
};
void setExtraCookieSpec(const std::string& spec);
void setTrustedProxies(const std::vector<std::string>& ips, const std::string& realipheader);
template<typename Func>
void wrapGetOrPost(bool getOrPost, const std::set<Capability>& caps, const std::string& pattern, Func f) {
auto func = [f, this, caps](const httplib::Request &req, httplib::Response &res) {
std::string user;
try {
user = d_sessions.getUser(req, getIP(req));
}
catch(std::exception& e) {
// cout<<"Error getting user from session: "<<e.what()<<endl;
}
for(const auto& c: caps) {
if(!d_users.userHasCap(user, c, &req))
throw std::runtime_error(fmt::format("Lacked a capability ({})", (int)c));
}
ComboReq cr{d_lsqw, req, res, d_users, d_sessions, *this, user};
auto output = f(cr);
if constexpr (std::is_same_v<decltype(output), std::pair<std::string, std::string>>) {
res.set_content(output.first, output.second);
}
else {
res.set_content(output.dump(), "application/json");
}
};
getOrPost ? d_svr.Get(pattern, func) : d_svr.Post(pattern, func);
}
template<typename func>
void wrapGet(const std::set<Capability>& caps, const std::string& pattern, func f) { wrapGetOrPost(true, caps, pattern, f); };
template<typename func>
void wrapPost(const std::set<Capability>& caps, const std::string& pattern, func f) { wrapGetOrPost(false, caps, pattern, f); };
void standardFunctions();
};