The Battle for Wesnoth  1.19.0-dev
server.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2015 - 2024
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 
34 namespace campaignd {
35 
36 /**
37  * Legacy add-ons server.
38  */
39 class server : public server_base
40 {
41 public:
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 
99 private:
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. */
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 
130  std::string feedback_url_format_;
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&);
232  void handle_request_campaign_list(const request&);//#TODO: rename with 'addon' later?
233  void handle_request_campaign(const request&);
234  void handle_request_campaign_hash(const request&);
235  void handle_request_terms(const request&);
236  void handle_upload(const request&);
237  void handle_delete(const request&);
238  void handle_change_passphrase(const request&);
239 
240  /**
241  * Send a client an informational message.
242  *
243  * The WML sent consists of a document containing a single @p [message]
244  * child with a @a message attribute holding the value of @a msg.
245  */
246  void send_message(const std::string& msg, const any_socket_ptr& sock);
247 
248  /**
249  * Send a client an error message.
250  *
251  * The WML sent consists of a document containing a single @p [error] child
252  * with a @a message attribute holding the value of @a msg. In addition to
253  * sending the error to the client, a line with the client IP and message
254  * is recorded to the server log.
255  */
256  void send_error(const std::string& msg, const any_socket_ptr& sock);
257 
258  /**
259  * Send a client an error message.
260  *
261  * The WML sent consists of a document containing a single @p [error] child
262  * with a @a message attribute holding the value of @a msg, an
263  * @a extra_data attribute holding the value of @a extra_data, and a
264  * @a status_code attribute holding the value of @a status_code. In
265  * addition to sending the error to the client, a line with the client IP
266  * and message is recorded to the server log.
267  */
268  void send_error(const std::string& msg, const std::string& extra_data, unsigned int status_code, const any_socket_ptr& sock);
269 
270  /**
271  * Check whether the provided passphrase matches the add-on and its author by checked against the forum database.
272  *
273  * @param addon The add-on uploaded, which contains the username to use.
274  * @param passphrase The passphrase to use for authentication.
275  * @param is_delete Whether the authentication is being requested for an add-on upload or an add-on deletion.
276  * @return Whether the provided information matches what's in the forum database.
277  */
278  bool authenticate_forum(const config& addon, const std::string& passphrase, bool is_delete);
279 };
280 
281 } // 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
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:1265
void handle_upload(const request &)
Definition: server.cpp:1468
std::string web_url_
Definition: server.hpp:132
void delete_addon(const std::string &id)
Definition: server.cpp:892
std::set< std::string > capabilities_
Definition: server.hpp:105
config cfg_
Server config.
Definition: server.hpp:113
void handle_request_terms(const request &)
Definition: server.cpp:1251
void send_error(const std::string &msg, const any_socket_ptr &sock)
Send a client an error message.
Definition: server.cpp:852
std::string license_notice_
Definition: server.hpp:133
void load_blacklist()
Reads the add-ons upload blacklist from WML.
Definition: server.cpp:746
std::map< std::string, std::string > hooks_
Definition: server.hpp:125
server & operator=(const config &server)=delete
void handle_new_client(socket_ptr socket)
Definition: server.cpp:489
const config & server_info() const
Retrieves the contents of the [server_info] WML node.
Definition: server.hpp:210
std::string blacklist_file_
Definition: server.hpp:136
std::unique_ptr< user_handler > user_handler_
Definition: server.hpp:101
void handle_server_id(const request &)
Definition: server.cpp:940
void handle_delete(const request &)
Definition: server.cpp:1836
void write_config()
Writes the server configuration WML back to disk.
Definition: server.cpp:769
void mark_dirty(const std::string &addon)
Definition: server.hpp:185
void send_message(const std::string &msg, const any_socket_ptr &sock)
Send a client an informational message.
Definition: server.cpp:840
optional_config get_addon(const std::string &id)
Retrieves an addon by id if found, or a null config otherwise.
Definition: server.cpp:882
void handle_request_campaign_hash(const request &)
Definition: server.cpp:1205
void handle_flush(const boost::system::error_code &error)
Definition: server.cpp:736
std::function< void(server *, const request &req)> request_handler
Definition: server.hpp:102
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:730
friend std::ostream & operator<<(std::ostream &o, const request &r)
Definition: server.cpp:483
std::unordered_map< std::string, config > addons_
The hash map of addons metadata.
Definition: server.hpp:108
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:828
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_read_from_fifo(const boost::system::error_code &error, std::size_t bytes_transferred)
Definition: server.cpp:539
const std::string cfg_file_
Definition: server.hpp:114
void serve_requests(Socket socket, boost::asio::yield_context yield)
Definition: server.cpp:504
void fire(const std::string &hook, const std::string &addon)
Fires a hook script.
Definition: server.cpp:789
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:1918
time_t update_pack_lifespan_
Definition: server.hpp:118
void handle_change_passphrase(const request &)
Definition: server.cpp:1887
std::vector< std::string > stats_exempt_ips_
Definition: server.hpp:138
void handle_request_campaign(const request &)
Definition: server.cpp:1061
void load_config()
Reads the server configuration from WML.
Definition: server.cpp:329
server(const std::string &cfg_file, unsigned short port=0)
Definition: server.cpp:275
bool strict_versions_
Definition: server.hpp:120
void handle_sighup(const boost::system::error_code &error, int signal_number)
Definition: server.cpp:717
void register_handlers()
Registers client request handlers.
Definition: server.cpp:928
void handle_request_campaign_list(const request &)
Definition: server.cpp:960
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:159
const config & child_or_empty(config_key_type key) const
Returns the first child with the given key, or an empty config if there is none.
Definition: config.cpp:395
Base class for implementing servers that use gzipped-WML network protocol.
Definition: server_base.hpp:80
std::string client_address(const any_socket_ptr &sock)
Definition: server.cpp:848
static void msg(const char *act, debug_info &i, const char *to="", const char *result="")
Definition: debugger.cpp:109
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
Definition: server_base.hpp:51
utils::variant< socket_ptr, tls_socket_ptr > any_socket_ptr
Definition: server_base.hpp:52
std::shared_ptr< boost::asio::ip::tcp::socket > socket_ptr
Definition: server_base.hpp:48
Client request information object.
Definition: server.hpp:57
const config & cfg
Definition: server.hpp:59
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
Definition: validation.hpp:33