Add minetest.is_valid_player_name utility

This commit is contained in:
Lars Mueller 2024-08-13 02:50:36 +02:00 committed by sfan5
parent 44db47e64a
commit d3ca269c79
7 changed files with 32 additions and 15 deletions

@ -7097,6 +7097,8 @@ Misc.
* `minetest.is_player(obj)`: boolean, whether `obj` is a player * `minetest.is_player(obj)`: boolean, whether `obj` is a player
* `minetest.player_exists(name)`: boolean, whether player exists * `minetest.player_exists(name)`: boolean, whether player exists
(regardless of online status) (regardless of online status)
* `minetest.is_valid_player_name(name)`: boolean, whether the given name
could be used as a player name (regardless of whether said player exists).
* `minetest.hud_replace_builtin(name, hud_definition)` * `minetest.hud_replace_builtin(name, hud_definition)`
* Replaces definition of a builtin hud element * Replaces definition of a builtin hud element
* `name`: `"breath"`, `"health"` or `"minimap"` * `name`: `"breath"`, `"health"` or `"minimap"`
@ -7989,9 +7991,9 @@ child will follow movement and rotation of that bone.
* `set_observers(observers)`: sets observers (players this object is sent to) * `set_observers(observers)`: sets observers (players this object is sent to)
* If `observers` is `nil`, the object's observers are "unmanaged": * If `observers` is `nil`, the object's observers are "unmanaged":
The object is sent to all players as governed by server settings. This is the default. The object is sent to all players as governed by server settings. This is the default.
* `observers` is a "set" of player names: `{[player name] = true, [other player name] = true, ...}` * `observers` is a "set" of player names: `{name1 = true, name2 = true, ...}`
* A set is a table where the keys are the elements of the set (in this case, player names) * A set is a table where the keys are the elements of the set
and the values are all `true`. (in this case, *valid* player names) and the values are all `true`.
* Attachments: The *effective observers* of an object are made up of * Attachments: The *effective observers* of an object are made up of
all players who can observe the object *and* are also effective observers all players who can observe the object *and* are also effective observers
of its parent object (if there is one). of its parent object (if there is one).

@ -1095,13 +1095,9 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
if (cmd_args.exists("terminal")) { if (cmd_args.exists("terminal")) {
#if USE_CURSES #if USE_CURSES
bool name_ok = true;
std::string admin_nick = g_settings->get("name"); std::string admin_nick = g_settings->get("name");
name_ok = name_ok && !admin_nick.empty(); if (!is_valid_player_name(admin_nick)) {
name_ok = name_ok && string_allowed(admin_nick, PLAYERNAME_ALLOWED_CHARS);
if (!name_ok) {
if (admin_nick.empty()) { if (admin_nick.empty()) {
errorstream << "No name given for admin. " errorstream << "No name given for admin. "
<< "Please check your minetest.conf that it " << "Please check your minetest.conf that it "
@ -1110,7 +1106,8 @@ static bool run_dedicated_server(const GameParams &game_params, const Settings &
} else { } else {
errorstream << "Name for admin '" errorstream << "Name for admin '"
<< admin_nick << "' is not valid. " << admin_nick << "' is not valid. "
<< "Please check that it only contains allowed characters. " << "Please check that it only contains allowed characters "
<< "and that it is at most 20 characters long. "
<< "Valid characters are: " << PLAYERNAME_ALLOWED_CHARS_USER_EXPL << "Valid characters are: " << PLAYERNAME_ALLOWED_CHARS_USER_EXPL
<< std::endl; << std::endl;
} }

@ -30,6 +30,10 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "porting.h" // strlcpy #include "porting.h" // strlcpy
bool is_valid_player_name(std::string_view name) {
return !name.empty() && name.size() <= PLAYERNAME_SIZE && string_allowed(name, PLAYERNAME_ALLOWED_CHARS);
}
Player::Player(const std::string &name, IItemDefManager *idef): Player::Player(const std::string &name, IItemDefManager *idef):
inventory(idef) inventory(idef)
{ {

@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "constants.h" #include "constants.h"
#include "network/networkprotocol.h" #include "network/networkprotocol.h"
#include "util/basic_macros.h" #include "util/basic_macros.h"
#include "util/string.h"
#include <list> #include <list>
#include <mutex> #include <mutex>
#include <functional> #include <functional>
@ -35,6 +36,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_" #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_"
#define PLAYERNAME_ALLOWED_CHARS_USER_EXPL "'a' to 'z', 'A' to 'Z', '0' to '9', '-', '_'" #define PLAYERNAME_ALLOWED_CHARS_USER_EXPL "'a' to 'z', 'A' to 'Z', '0' to '9', '-', '_'"
bool is_valid_player_name(std::string_view name);
struct PlayerFovSpec struct PlayerFovSpec
{ {
f32 fov; f32 fov;

@ -859,12 +859,8 @@ int ObjectRef::l_set_observers(lua_State *L)
lua_pushnil(L); lua_pushnil(L);
while (lua_next(L, 2) != 0) { while (lua_next(L, 2) != 0) {
std::string name = readParam<std::string>(L, -2); std::string name = readParam<std::string>(L, -2);
if (name.empty()) if (!is_valid_player_name(name))
throw LuaError("Observer name is empty"); throw LuaError("Observer name is not a valid player name");
if (name.size() > PLAYERNAME_SIZE)
throw LuaError("Observer name is too long");
if (!string_allowed(name, PLAYERNAME_ALLOWED_CHARS))
throw LuaError("Observer name contains invalid characters");
if (!lua_toboolean(L, -1)) // falsy value? if (!lua_toboolean(L, -1)) // falsy value?
throw LuaError("Values in the `observers` table need to be true"); throw LuaError("Values in the `observers` table need to be true");
observer_names.insert(std::move(name)); observer_names.insert(std::move(name));

@ -44,6 +44,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
#include "util/sha1.h" #include "util/sha1.h"
#include "my_sha256.h" #include "my_sha256.h"
#include "util/png.h" #include "util/png.h"
#include "player.h"
#include <cstdio> #include <cstdio>
// only available in zstd 1.3.5+ // only available in zstd 1.3.5+
@ -674,6 +675,16 @@ int ModApiUtil::l_urlencode(lua_State *L)
return 1; return 1;
} }
// is_valid_player_name(name)
int ModApiUtil::l_is_valid_player_name(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
auto s = readParam<std::string_view>(L, 1);
lua_pushboolean(L, is_valid_player_name(s));
return 1;
}
void ModApiUtil::Initialize(lua_State *L, int top) void ModApiUtil::Initialize(lua_State *L, int top)
{ {
API_FCT(log); API_FCT(log);
@ -722,6 +733,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(set_last_run_mod); API_FCT(set_last_run_mod);
API_FCT(urlencode); API_FCT(urlencode);
API_FCT(is_valid_player_name);
LuaSettings::create(L, g_settings, g_settings_path); LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings"); lua_setfield(L, top, "settings");

@ -134,6 +134,9 @@ private:
// urlencode(value) // urlencode(value)
static int l_urlencode(lua_State *L); static int l_urlencode(lua_State *L);
// is_valid_player_name(name)
static int l_is_valid_player_name(lua_State *L);
public: public:
static void Initialize(lua_State *L, int top); static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top); static void InitializeAsync(lua_State *L, int top);