The Battle for Wesnoth  1.19.7+dev
forum_user_handler.hpp
Go to the documentation of this file.
1 /*
2  Copyright (C) 2008 - 2024
3  by Thomas Baumhauer <thomas.baumhauer@NOSPAMgmail.com>
4  Part of the Battle for Wesnoth Project https://www.wesnoth.org/
5 
6  This program is free software; you can redistribute it and/or modify
7  it under the terms of the GNU General Public License as published by
8  the Free Software Foundation; either version 2 of the License, or
9  (at your option) any later version.
10  This program is distributed in the hope that it will be useful,
11  but WITHOUT ANY WARRANTY.
12 
13  See the COPYING file for more details.
14 */
15 
16 #pragma once
17 
19 #include "server/common/dbconn.hpp"
20 
21 #include <chrono>
22 #include <vector>
23 #include <memory>
24 
25 /**
26  * A class to handle the non-SQL logic for connecting to the phpbb forum database.
27  */
28 class fuh : public user_handler
29 {
30 public:
31  /**
32  * Reads wesnothd's config for the data needed to initialize this class and @ref dbconn.
33  */
34  fuh(const config& c);
35 
36  /**
37  * Retrieves the player's hashed password from the phpbb forum database and checks if it matches the hashed password sent by the client.
38  *
39  * @param name The username used to login.
40  * @param password The hashed password sent by the client.
41  * @see server::send_password_request().
42  * @return Whether the hashed password sent by the client matches the hash retrieved from the phpbb database.
43  */
44  bool login(const std::string& name, const std::string& password);
45 
46  /**
47  * Needed because the hashing algorithm used by phpbb requires some info
48  * from the original hash to recreate the same hash
49  *
50  * @return the salt, or an empty string if an error occurs.
51  */
52  std::string extract_salt(const std::string& name);
53 
54  /**
55  * Sets the last login time to the current time.
56  *
57  * @param name The player's username.
58  */
59  void user_logged_in(const std::string& name);
60 
61  /**
62  * @param name The player's username.
63  * @return Whether the player's username is exists in the forum database.
64  */
65  bool user_exists(const std::string& name);
66 
67  /**
68  * @param name The player's username.
69  * @return The phpbb USER_ID value created when the player registers on the forums.
70  * @note wesnothd allows the same player to login with multiple clients using the same username but with different case letters (ie: abc and ABC).
71  * This means that this value is not necessarily unique among all connected clients.
72  */
73  long get_forum_id(const std::string& name);
74 
75  /**
76  * @param name The player's username.
77  * @return Whether the username has been activated.
78  */
79  bool user_is_active(const std::string& name);
80 
81  /**
82  * @param name The player's username.
83  * @return Whether the user is a moderator or not.
84  * @note This can be either from the extra table or whether the player is a member of the MP Moderators groups.
85  */
86  bool user_is_moderator(const std::string& name);
87 
88  /**
89  * Sets or unsets whether the player should be considered a moderator in the extra table.
90  *
91  * @param name The player's username.
92  * @param is_moderator The moderator value to set.
93  */
94  void set_is_moderator(const std::string& name, const bool& is_moderator);
95 
96  /**
97  * @param name The player's username.
98  * @param addr The IP address being checked.
99  * @return Whether the user is banned, and if so then how long. See also @ref user_handler::ban_info().
100  * @note This checks for bans by username, the email associated to the username, and IP address.
101  * @note Glob IP and email address bans are NOT supported yet since they require a different kind of query that isn't supported
102  * by our prepared SQL statement API right now. However, they are basically never used on forums.wesnoth.org,
103  * so this shouldn't be a problem.
104  */
105  ban_info user_is_banned(const std::string& name, const std::string& addr);
106 
107  /**
108  * @param name The player's username.
109  * @return A string containing basic information about the player.
110  */
111  std::string user_info(const std::string& name);
112 
113  /**
114  * @return A unique UUID from the backing database.
115  */
116  std::string get_uuid();
117 
118  /**
119  * @return A list of active tournaments pulled from the Tournaments subforum.
120  */
121  std::string get_tournaments();
122 
123  /**
124  * Runs an asynchronous query to fetch the user's game history data.
125  * The result is then posted back to the main boost::asio thread to be sent to the requesting player.
126  *
127  * @param io_service The boost io_service to use to post the query results back to the main boost::asio thread.
128  * @param s The server instance the player is connected to.
129  * @param socket The socket used to communicate with the player's client.
130  * @param player_id The forum ID of the player to get the game history for.
131  * @param offset Where to start returning rows to the client from the query results.
132  * @param search_game_name Query for games matching this name. Supports leading and/or trailing wildcards.
133  * @param search_content_type The content type to query for (ie: scenario)
134  * @param search_content Query for games using this content ID. Supports leading and/or trailing wildcards.
135  */
136  void async_get_and_send_game_history(boost::asio::io_context& io_service, wesnothd::server& s, any_socket_ptr socket, int player_id, int offset, std::string& search_game_name, int search_content_type, std::string& search_content);
137 
138  /**
139  * Inserts game related information.
140  *
141  * @param uuid The value returned by @ref get_uuid().
142  * @param game_id The game's db_id.
143  * @param version The version of wesnothd running this game.
144  * @param name The game's name as entered by the user.
145  * @param reload Whether this game was loaded from the save of a previous game.
146  * @param observers Whether observers are allowed.
147  * @param is_public Whether the game's replay will be publicly available.
148  * @param has_password Whether the game has a password.
149  */
150  void db_insert_game_info(const std::string& uuid, int game_id, const std::string& version, const std::string& name, int reload, int observers, int is_public, int has_password);
151 
152  /**
153  * Update the game related information when the game ends.
154  *
155  * @param uuid The value returned by @ref get_uuid().
156  * @param game_id The game's db_id.
157  * @param replay_location The location of the game's publicly available replay.
158  */
159  void db_update_game_end(const std::string& uuid, int game_id, const std::string& replay_location);
160 
161  /**
162  * Inserts player information per side.
163  *
164  * @param uuid The value returned by @ref get_uuid().
165  * @param game_id The game's db_id.
166  * @param username The username of the player who owns this side.
167  * @param side_number This side's side number.
168  * @param is_host Whether this player is the host.
169  * @param faction The name of this side's faction.
170  * @param version The version of Wesnoth this player is using.
171  * @param source The source where this player downloaded Wesnoth (ie: Steam, SourceForge, etc).
172  * @param current_user The player currently in control of this side.
173  * @param leaders The comma-delimited list of leader unit types for that side.
174  */
175  void db_insert_game_player_info(const std::string& uuid, int game_id, const std::string& username, int side_number, int is_host, const std::string& faction, const std::string& version, const std::string& source, const std::string& current_user, const std::string& leaders);
176 
177  /**
178  * Inserts information about the content being played.
179  *
180  * @param uuid The value returned by @ref get_uuid().
181  * @param game_id The game's db_id.
182  * @param type The add-on content's type (ie: era, scenario, etc).
183  * @param name The name of the content.
184  * @param id The id of the content.
185  * @param addon_id The id of the addon that the content is from.
186  * @param addon_version The version of the add-on.
187  * @return The number of rows inserted which should always be 1.
188  */
189  unsigned long long db_insert_game_content_info(const std::string& uuid, int game_id, const std::string& type, const std::string& name, const std::string& id, const std::string& addon_id, const std::string& addon_version);
190 
191  /**
192  * Sets the OOS flag in the database if wesnothd is told by a client it has detected an OOS error.
193  *
194  * @param uuid The value returned by @ref get_uuid().
195  * @param game_id The game's db_id.
196  */
197  void db_set_oos_flag(const std::string& uuid, int game_id);
198 
199  /**
200  * A simple test query for running a query asynchronously.
201  * The main point is that it takes a meaningful amount of time to complete so that it's easy to see that multiple are running at once and are finishing out of order.
202  *
203  * @param io_service The boost io_service to use to post the query results back to the main boost::asio thread.
204  * @param limit How many recursions to make in the query.
205  */
206  void async_test_query(boost::asio::io_context& io_service, int limit);
207 
208  /**
209  * Checks whether a forum thread with @a topic_id exists.
210  *
211  * @param topic_id The topic id to check for.
212  * @return True if the thread exists or there was a database failure, false if the topic wasn't found.
213  */
214  bool db_topic_id_exists(int topic_id);
215 
216  /**
217  * Inserts information about an uploaded add-on into the database.
218  *
219  * @param instance_version The version of campaignd the add-on was uploaded to.
220  * @param id The add-on's ID (aka directory name).
221  * @param name The add-on's name from the pbl.
222  * @param type The add-on's type from the pbl.
223  * @param version The add-on's version from the pbl.
224  * @param forum_auth Whether the provided author and password should be matched a forum account or not.
225  * @param topic_id The forum topic ID of the add-on's feedback thread, 0 if not present.
226  * @param uploader The person uploading this version of the add-on.
227  */
228  void db_insert_addon_info(const std::string& instance_version, const std::string& id, const std::string& name, const std::string& type, const std::string& version, bool forum_auth, int topic_id, const std::string uploader);
229 
230  /**
231  * Inserts into the database for when a player logs in.
232  *
233  * @param username The username of who logged in. The username is converted to lower case when inserting in order to allow index usage when querying.
234  * @param ip The ip address of who logged in.
235  * @param version The version of the client that logged in.
236  */
237  unsigned long long db_insert_login(const std::string& username, const std::string& ip, const std::string& version);
238 
239  /**
240  * Updates the database for when a player logs out.
241  *
242  * @param login_id The generated ID that uniquely identifies the row to be updated.
243  */
244  void db_update_logout(unsigned long long login_id);
245 
246  /**
247  * Searches for all players that logged in using the ip address.
248  * The '%' wildcard can be used to search for partial ip addresses.
249  *
250  * @param ip The ip address to search for.
251  * @param out Where to output the results.
252  */
253  void get_users_for_ip(const std::string& ip, std::ostringstream* out);
254 
255  /**
256  * Searches for all ip addresses used by the player.
257  * The username is converted to lower case to allow a case insensitive select query to be executed while still using an index.
258  * The '%' wildcard can be used to search for partial usernames.
259  *
260  * @param username The username to search for.
261  * @param out Where to output the results.
262  */
263  void get_ips_for_user(const std::string& username, std::ostringstream* out);
264 
265  /**
266  * @param user The player's username.
267  * @return The player's email address from the phpbb forum database.
268  */
269  std::string get_user_email(const std::string& user);
270 
271  /**
272  * Increments the download count for this add-on for the specific version.
273  *
274  * @param instance_version The version of campaignd the add-on was uploaded to.
275  * @param id The add-on's ID (aka directory name).
276  * @param version The version of the add-on being downloaded. May not be the most recent version.
277  */
278  void db_update_addon_download_count(const std::string& instance_version, const std::string& id, const std::string& version);
279 
280  /**
281  * Checks whether the provided username is the primary author of the add-on.
282  *
283  * @param instance_version Which major version this is for (1.16, 1.17, etc).
284  * @param id The ID of the add-on.
285  * @param username The username attempting to do something with the add-on.
286  * @return true if the user is the primary author of an addon, false otherwise.
287  */
288  bool db_is_user_primary_author(const std::string& instance_version, const std::string& id, const std::string& username);
289 
290  /**
291  * Checks whether the provided username is a secondary author of the add-on.
292  *
293  * @param instance_version Which major version this is for (1.16, 1.17, etc).
294  * @param id The ID of the add-on.
295  * @param username The username attempting to do something with the add-on.
296  * @return true if the user is a secondary author of an addon, false otherwise.
297  */
298  bool db_is_user_secondary_author(const std::string& instance_version, const std::string& id, const std::string& username);
299 
300  /**
301  * Removes the authors information from addon_author for a particular addon and version.
302  *
303  * @param instance_version Which major version this is for (1.16, 1.17, etc).
304  * @param id The ID of the add-on.
305  */
306  void db_delete_addon_authors(const std::string& instance_version, const std::string& id);
307 
308  /**
309  * Inserts rows for the primary and secondary authors for a particular addon and version.
310  *
311  * @param instance_version Which major version this is for (1.16, 1.17, etc).
312  * @param id The ID of the add-on.
313  * @param primary_authors The primary authors of the add-on.
314  * @param secondary_authors The secondary authors of the add-on.
315  */
316  void db_insert_addon_authors(const std::string& instance_version, const std::string& id, const std::vector<std::string>& primary_authors, const std::vector<std::string>& secondary_authors);
317 
318  /**
319  * Checks whether any author information exists for a particular addon and version, since if there's no author information then of course no primary or secondary authors will ever be found.
320  *
321  * @param instance_version Which major version this is for (1.16, 1.17, etc).
322  * @param id The ID of the add-on.
323  * @return true if any author information exists for this addon, false otherwise.
324  */
325  bool db_do_any_authors_exist(const std::string& instance_version, const std::string& id);
326 
327 private:
328  /** An instance of the class responsible for executing the queries and handling the database connection. */
330  /** The name of the phpbb users table */
331  std::string db_users_table_;
332  /** The name of the extras custom table, not part of a phpbb database */
333  std::string db_extra_table_;
334  /** The group ID of the forums MP Moderators group */
336 
337  /**
338  * @param user The player's username.
339  * @return The player's hashed password from the phpbb forum database.
340  */
341  std::string get_hashed_password_from_db(const std::string& user);
342 
343  /**
344  * @param user The player's username.
345  * @return The player's last login time.
346  */
347  std::chrono::system_clock::time_point get_lastlogin(const std::string& user);
348 
349  /**
350  * @param user The player's username.
351  * @return The player's forum registration date.
352  */
353  std::chrono::system_clock::time_point get_registrationdate(const std::string& user);
354 };
A config object defines a single node in a WML file, with access to child nodes.
Definition: config.hpp:172
This class is responsible for handling the database connections as well as executing queries and hand...
Definition: dbconn.hpp:40
A class to handle the non-SQL logic for connecting to the phpbb forum database.
void async_get_and_send_game_history(boost::asio::io_context &io_service, wesnothd::server &s, any_socket_ptr socket, int player_id, int offset, std::string &search_game_name, int search_content_type, std::string &search_content)
Runs an asynchronous query to fetch the user's game history data.
void db_set_oos_flag(const std::string &uuid, int game_id)
Sets the OOS flag in the database if wesnothd is told by a client it has detected an OOS error.
std::string get_uuid()
std::string db_users_table_
The name of the phpbb users table.
bool user_is_moderator(const std::string &name)
void db_delete_addon_authors(const std::string &instance_version, const std::string &id)
Removes the authors information from addon_author for a particular addon and version.
void db_insert_addon_info(const std::string &instance_version, const std::string &id, const std::string &name, const std::string &type, const std::string &version, bool forum_auth, int topic_id, const std::string uploader)
Inserts information about an uploaded add-on into the database.
std::string get_hashed_password_from_db(const std::string &user)
void set_is_moderator(const std::string &name, const bool &is_moderator)
Sets or unsets whether the player should be considered a moderator in the extra table.
long get_forum_id(const std::string &name)
int mp_mod_group_
The group ID of the forums MP Moderators group.
void get_users_for_ip(const std::string &ip, std::ostringstream *out)
Searches for all players that logged in using the ip address.
std::chrono::system_clock::time_point get_registrationdate(const std::string &user)
bool db_topic_id_exists(int topic_id)
Checks whether a forum thread with topic_id exists.
ban_info user_is_banned(const std::string &name, const std::string &addr)
std::string db_extra_table_
The name of the extras custom table, not part of a phpbb database.
void db_update_game_end(const std::string &uuid, int game_id, const std::string &replay_location)
Update the game related information when the game ends.
std::string get_user_email(const std::string &user)
void async_test_query(boost::asio::io_context &io_service, int limit)
A simple test query for running a query asynchronously.
std::string extract_salt(const std::string &name)
Needed because the hashing algorithm used by phpbb requires some info from the original hash to recre...
std::chrono::system_clock::time_point get_lastlogin(const std::string &user)
void db_update_addon_download_count(const std::string &instance_version, const std::string &id, const std::string &version)
Increments the download count for this add-on for the specific version.
bool db_is_user_secondary_author(const std::string &instance_version, const std::string &id, const std::string &username)
Checks whether the provided username is a secondary author of the add-on.
std::string get_tournaments()
void db_insert_addon_authors(const std::string &instance_version, const std::string &id, const std::vector< std::string > &primary_authors, const std::vector< std::string > &secondary_authors)
Inserts rows for the primary and secondary authors for a particular addon and version.
void user_logged_in(const std::string &name)
Sets the last login time to the current time.
void get_ips_for_user(const std::string &username, std::ostringstream *out)
Searches for all ip addresses used by the player.
bool login(const std::string &name, const std::string &password)
Retrieves the player's hashed password from the phpbb forum database and checks if it matches the has...
fuh(const config &c)
Reads wesnothd's config for the data needed to initialize this class and dbconn.
bool user_is_active(const std::string &name)
std::string user_info(const std::string &name)
bool db_do_any_authors_exist(const std::string &instance_version, const std::string &id)
Checks whether any author information exists for a particular addon and version, since if there's no ...
bool db_is_user_primary_author(const std::string &instance_version, const std::string &id, const std::string &username)
Checks whether the provided username is the primary author of the add-on.
unsigned long long db_insert_login(const std::string &username, const std::string &ip, const std::string &version)
Inserts into the database for when a player logs in.
void db_insert_game_player_info(const std::string &uuid, int game_id, const std::string &username, int side_number, int is_host, const std::string &faction, const std::string &version, const std::string &source, const std::string &current_user, const std::string &leaders)
Inserts player information per side.
dbconn conn_
An instance of the class responsible for executing the queries and handling the database connection.
bool user_exists(const std::string &name)
unsigned long long db_insert_game_content_info(const std::string &uuid, int game_id, const std::string &type, const std::string &name, const std::string &id, const std::string &addon_id, const std::string &addon_version)
Inserts information about the content being played.
void db_update_logout(unsigned long long login_id)
Updates the database for when a player logs out.
void db_insert_game_info(const std::string &uuid, int game_id, const std::string &version, const std::string &name, int reload, int observers, int is_public, int has_password)
Inserts game related information.
An interface class to handle nick registration To activate it put a [user_handler] section into the s...
int side_number
Definition: game_info.hpp:40
utils::variant< socket_ptr, tls_socket_ptr > any_socket_ptr
Definition: server_base.hpp:53
Ban status description.
mock_char c
static map_location::direction s