The Battle for Wesnoth 1.21.0-dev
 
Loading...
Searching...
No Matches
server.hpp
Go to the documentation of this file.
1/*
2 Copyright (C) 2015 - 2025
3 by Iris Morelle <shadowm2006@gmail.com>
4 Copyright (C) 2003 - 2018 by David White <dave@whitevine.net>
5 Part of the Battle for Wesnoth Project https://www.wesnoth.org/
6
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
11 This program is distributed in the hope that it will be useful,
12 but WITHOUT ANY WARRANTY.
13
14 See the COPYING file for more details.
15*/
16
17#pragma once
18
19#include "addon/validation.hpp"
24
25#include <boost/asio/basic_waitable_timer.hpp>
26
27#include <chrono>
28#include <functional>
29#include <iosfwd>
30#include <set>
31#include <unordered_map>
32#include <unordered_set>
33
34namespace campaignd {
35
36/**
37 * Legacy add-ons server.
38 */
39class server : public server_base
40{
41public:
42 explicit server(const std::string& cfg_file,
43 unsigned short port = 0);
44 server(const config& server) = delete;
45 ~server();
46
47 server& operator=(const config& server) = delete;
48
49 /**
50 * Client request information object.
51 *
52 * Contains data and metadata associated with a single request from a
53 * remote add-ons client, in a light-weight format for passing to request
54 * handlers.
55 */
56 struct request
57 {
58 const std::string& cmd;
59 const config& cfg;
60
62 const std::string addr;
63
64 /**
65 * context of the coroutine the request is executed in
66 * async operations on @a sock can use it instead of a handler.
67 */
68 boost::asio::yield_context yield;
69
70 /**
71 * Constructor.
72 *
73 * @param reqcmd Request command.
74 * @param reqcfg Request WML body.
75 * @param reqsock Client socket that initiated the request.
76 * @param yield The function will suspend on write operation using this yield context
77 *
78 * @note Neither @a reqcmd nor @a reqcfg are copied into instances, so
79 * they are required to exist for as long as every @a request
80 * instance that uses them. Furthermore, @a reqcfg MUST NOT REFER
81 * TO A CONST OBJECT, since some code may modify it directly for
82 * performance reasons.
83 */
84 template<class Socket>
85 request(const std::string& reqcmd,
86 config& reqcfg,
87 Socket reqsock,
88 boost::asio::yield_context yield)
89 : cmd(reqcmd)
90 , cfg(reqcfg)
91 , sock(reqsock)
92 , addr(client_address(reqsock))
93 , yield(yield)
94 {}
95 };
96
97 friend std::ostream& operator<<(std::ostream& o, const request& r);
98
99private:
100
101 std::unique_ptr<user_handler> user_handler_;
102 typedef std::function<void (server*, const request& req)> request_handler;
103 typedef std::map<std::string, request_handler> request_handlers_table;
104
105 std::set<std::string> capabilities_;
106
107 /**The hash map of addons metadata*/
108 std::unordered_map<std::string, config> addons_;
109 /**The set of unique addon names with pending metadata updates*/
110 std::unordered_set<std::string> dirty_addons_;
111
112 /**Server config*/
114 const std::string cfg_file_;
115
117 int compress_level_; /**< Used for add-on archives. */
118 std::chrono::seconds update_pack_lifespan_;
119
121
122 /** Default upload size limit in bytes. */
123 static const std::size_t default_document_size_limit = 100 * 1024 * 1024;
124
125 std::map<std::string, std::string> hooks_;
127
128 std::string server_id_;
129
131
132 std::string web_url_;
133 std::string license_notice_;
134
136 std::string blacklist_file_;
137
138 std::vector<std::string> stats_exempt_ips_;
139
140 boost::asio::basic_waitable_timer<std::chrono::steady_clock> flush_timer_;
141
142 void handle_new_client(socket_ptr socket);
144
145 template<class Socket>
146 void serve_requests(Socket socket, boost::asio::yield_context yield);
147
148#ifndef _WIN32
149 void handle_read_from_fifo(const boost::system::error_code& error, std::size_t bytes_transferred);
150
151 void handle_sighup(const boost::system::error_code& error, int signal_number);
152#endif
153
154 /**
155 * Starts timer to write config to disk every ten minutes.
156 */
157 void flush_cfg();
158 void handle_flush(const boost::system::error_code& error);
159
160 /**
161 * Reads the server configuration from WML.
162 */
163 void load_config();
164
165 /**
166 * Writes the server configuration WML back to disk.
167 */
168 void write_config();
169
170 /**
171 * Reads the add-ons upload blacklist from WML.
172 */
173 void load_blacklist();
174
175 /**
176 * Fires a hook script.
177 */
178 void fire(const std::string& hook, const std::string& addon);
179
180 /** Retrieves an addon by id if found, or a null config otherwise. */
181 optional_config get_addon(const std::string& id);
182
183 void delete_addon(const std::string& id);
184
185 void mark_dirty(const std::string& addon)
186 {
187 dirty_addons_.emplace(addon);
188 }
189
190 /**
191 * Performs validation on an incoming add-on.
192 *
193 * @param req Server request info, containing either a full
194 * WML pack, or a delta update pack.
195 * @param existing_addon Used to store a pointer to the existing add-on
196 * WML on the server if the add-on already exists.
197 * nullptr is stored otherwise.
198 * @param error_data Used to store extra error data for status codes
199 * other than ADDON_CHECK_STATUS::SUCCESS. Cleared
200 * otherwise.
201 *
202 * @return ADDON_CHECK_STATUS::SUCCESS if the validation checks pass, a
203 * more relevant value otherwise.
204 */
206 config*& existing_addon,
207 std::string& error_data);
208
209 /** Retrieves the contents of the [server_info] WML node. */
210 const config& server_info() const { return cfg_.child_or_empty("server_info"); }
211
212 /** Checks if the specified address should never bump download counts. */
213 bool ignore_address_stats(const std::string& addr) const;
214
215 //
216 // Request handling.
217 //
218
219 /**
220 * Registers client request handlers.
221 *
222 * This is called by the class constructor. Individual handlers must be
223 * methods of this class that take a single parameter of type @a request
224 * and they are registered using the @a register_handler method.
225 *
226 * When adding new handlers, make sure to update the implementation of
227 * this method accordingly so they are recognized and invoked at runtime.
228 */
229 void register_handlers();
230
231 void handle_server_id(const request& req);
232 void handle_request_campaign_list(const request& req);//#TODO: rename with 'addon' later?
233 void handle_request_campaign(const request& req);
234 void handle_request_campaign_hash(const request& req);
235 void handle_request_terms(const request& req);
236 void handle_upload(const request& req);
237 void handle_delete(const request& req);
238 void handle_change_passphrase(const request& req);
239 void handle_list_hidden(const server::request& req);
240 void handle_hide_addon(const request& req);
241 void handle_unhide_addon(const request& req);
242 void handle_addon_downloads_by_version(const request& req);
243 void handle_forum_auth_usage(const request& req);
244 void handle_admins_list(const request& req);
245
246 /**
247 * Send a client an informational message.
248 *
249 * The WML sent consists of a document containing a single @p [message]
250 * child with a @a message attribute holding the value of @a msg.
251 */
252 void send_message(const std::string& msg, const any_socket_ptr& sock);
253
254 /**
255 * Send a client an error message.
256 *
257 * The WML sent consists of a document containing a single @p [error] child
258 * with a @a message attribute holding the value of @a msg. In addition to
259 * sending the error to the client, a line with the client IP and message
260 * is recorded to the server log.
261 */
262 void send_error(const std::string& msg, const any_socket_ptr& sock);
263
264 /**
265 * Send a client an error message.
266 *
267 * The WML sent consists of a document containing a single @p [error] child
268 * with a @a message attribute holding the value of @a msg, an
269 * @a extra_data attribute holding the value of @a extra_data, and a
270 * @a status_code attribute holding the value of @a status_code. In
271 * addition to sending the error to the client, a line with the client IP
272 * and message is recorded to the server log.
273 */
274 void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, const any_socket_ptr& sock);
275
276 /**
277 * Check whether the provided passphrase matches the add-on and its author by checked against the forum database.
278 *
279 * @param addon The add-on uploaded, which contains the username to use.
280 * @param passphrase The passphrase to use for authentication.
281 * @param is_delete Whether the authentication is being requested for an add-on upload or an add-on deletion.
282 * @return Whether the provided information matches what's in the forum database.
283 */
284 bool authenticate_forum(const config& addon, const std::string& passphrase, bool is_delete);
285
286 /**
287 * @param username The username to check the passphrase against.
288 * @param passphrase The passphrase to use for authentication.
289 * @return Whether the provided username is an admin and the provided password matches.
290 */
291 bool authenticate_admin(const std::string& username, const std::string& passphrase);
292};
293
294} // end namespace campaignd
Add-on blacklist table.
Definition blacklist.hpp:43
Legacy add-ons server.
Definition server.hpp:40
request_handlers_table handlers_
Definition server.hpp:126
std::map< std::string, request_handler > request_handlers_table
Definition server.hpp:103
void handle_upload(const request &req)
Definition server.cpp:1476
ADDON_CHECK_STATUS validate_addon(const server::request &req, config *&existing_addon, std::string &error_data)
Performs validation on an incoming add-on.
Definition server.cpp:1261
std::string web_url_
Definition server.hpp:132
void delete_addon(const std::string &id)
Definition server.cpp:872
std::set< std::string > capabilities_
Definition server.hpp:105
config cfg_
Server config.
Definition server.hpp:113
void handle_unhide_addon(const request &req)
Definition server.cpp:1958
void handle_change_passphrase(const request &req)
Definition server.cpp:1898
void send_error(const std::string &msg, const any_socket_ptr &sock)
Send a client an error message.
Definition server.cpp:837
friend std::ostream & operator<<(std::ostream &o, const request &r)
Definition server.cpp:469
std::string license_notice_
Definition server.hpp:133
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
Definition server.hpp:210
void load_blacklist()
Reads the add-ons upload blacklist from WML.
Definition server.cpp:737
std::map< std::string, std::string > hooks_
Definition server.hpp:125
void handle_new_client(socket_ptr socket)
Definition server.cpp:475
std::string blacklist_file_
Definition server.hpp:136
bool authenticate_admin(const std::string &username, const std::string &passphrase)
Definition server.cpp:2092
std::unique_ptr< user_handler > user_handler_
Definition server.hpp:101
void handle_request_campaign_hash(const request &req)
Definition server.cpp:1201
void write_config()
Writes the server configuration WML back to disk.
Definition server.cpp:755
void mark_dirty(const std::string &addon)
Definition server.hpp:185
void handle_request_terms(const request &req)
Definition server.cpp:1247
void send_message(const std::string &msg, const any_socket_ptr &sock)
Send a client an informational message.
Definition server.cpp:826
optional_config get_addon(const std::string &id)
Retrieves an addon by id if found, or a null config otherwise.
Definition server.cpp:862
void handle_flush(const boost::system::error_code &error)
Definition server.cpp:727
std::function< void(server *, const request &req)> request_handler
Definition server.hpp:102
void handle_list_hidden(const server::request &req)
Definition server.cpp:1985
std::string feedback_url_format_
Definition server.hpp:130
void flush_cfg()
Starts timer to write config to disk every ten minutes.
Definition server.cpp:721
void handle_hide_addon(const request &req)
Definition server.cpp:1930
std::unordered_map< std::string, config > addons_
The hash map of addons metadata.
Definition server.hpp:108
void handle_addon_downloads_by_version(const request &req)
Definition server.cpp:2013
server(const config &server)=delete
std::unordered_set< std::string > dirty_addons_
The set of unique addon names with pending metadata updates.
Definition server.hpp:110
bool ignore_address_stats(const std::string &addr) const
Checks if the specified address should never bump download counts.
Definition server.cpp:814
blacklist blacklist_
Definition server.hpp:135
static const std::size_t default_document_size_limit
Default upload size limit in bytes.
Definition server.hpp:123
int compress_level_
Used for add-on archives.
Definition server.hpp:117
boost::asio::basic_waitable_timer< std::chrono::steady_clock > flush_timer_
Definition server.hpp:140
void handle_server_id(const request &req)
Definition server.cpp:926
void handle_read_from_fifo(const boost::system::error_code &error, std::size_t bytes_transferred)
Definition server.cpp:529
const std::string cfg_file_
Definition server.hpp:114
void serve_requests(Socket socket, boost::asio::yield_context yield)
Definition server.cpp:496
void handle_request_campaign(const request &req)
Definition server.cpp:1058
void fire(const std::string &hook, const std::string &addon)
Fires a hook script.
Definition server.cpp:775
void handle_new_client(tls_socket_ptr socket)
std::string server_id_
Definition server.hpp:128
bool authenticate_forum(const config &addon, const std::string &passphrase, bool is_delete)
Check whether the provided passphrase matches the add-on and its author by checked against the forum ...
Definition server.cpp:2067
server & operator=(const config &server)=delete
void handle_forum_auth_usage(const request &req)
Definition server.cpp:2031
std::vector< std::string > stats_exempt_ips_
Definition server.hpp:138
void handle_delete(const request &req)
Definition server.cpp:1842
void handle_request_campaign_list(const request &req)
Definition server.cpp:946
void load_config()
Reads the server configuration from WML.
Definition server.cpp:316
void handle_admins_list(const request &req)
Definition server.cpp:2049
std::chrono::seconds update_pack_lifespan_
Definition server.hpp:118
void handle_sighup(const boost::system::error_code &error, int signal_number)
Definition server.cpp:708
void register_handlers()
Registers client request handlers.
Definition server.cpp:908
A config object defines a single node in a WML file, with access to child nodes.
Definition config.hpp:157
const config & child_or_empty(std::string_view key) const
Returns the first child with the given key, or an empty config if there is none.
Definition config.cpp:390
Base class for implementing servers that use gzipped-WML network protocol.
std::string client_address(const any_socket_ptr &sock)
Definition server.cpp:833
Base class for servers using Wesnoth's WML over TCP protocol.
std::shared_ptr< boost::asio::ssl::stream< socket_ptr::element_type > > tls_socket_ptr
utils::variant< socket_ptr, tls_socket_ptr > any_socket_ptr
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Client request information object.
Definition server.hpp:57
request(const std::string &reqcmd, config &reqcfg, Socket reqsock, boost::asio::yield_context yield)
Constructor.
Definition server.hpp:85
const std::string & cmd
Definition server.hpp:58
const any_socket_ptr sock
Definition server.hpp:61
boost::asio::yield_context yield
context of the coroutine the request is executed in async operations on sock can use it instead of a ...
Definition server.hpp:68
const std::string addr
Definition server.hpp:62
ADDON_CHECK_STATUS