forked from Mirrorlandia_minetest/minetest
Add on_authplayer callback and 'last_login' to on_joinplayer (#9574)
Replace on_auth_fail callback with more versatile on_authplayer Better clarify account login process in Lua API documentation Change initial timestamp for newly registered accounts to -1
This commit is contained in:
parent
037422fdba
commit
15ba75e4cf
@ -41,7 +41,6 @@ core.builtin_auth_handler = {
|
|||||||
return {
|
return {
|
||||||
password = auth_entry.password,
|
password = auth_entry.password,
|
||||||
privileges = privileges,
|
privileges = privileges,
|
||||||
-- Is set to nil if unknown
|
|
||||||
last_login = auth_entry.last_login,
|
last_login = auth_entry.last_login,
|
||||||
}
|
}
|
||||||
end,
|
end,
|
||||||
@ -53,7 +52,7 @@ core.builtin_auth_handler = {
|
|||||||
name = name,
|
name = name,
|
||||||
password = password,
|
password = password,
|
||||||
privileges = core.string_to_privs(core.settings:get("default_privs")),
|
privileges = core.string_to_privs(core.settings:get("default_privs")),
|
||||||
last_login = os.time(),
|
last_login = -1, -- Defer login time calculation until record_login (called by on_joinplayer)
|
||||||
})
|
})
|
||||||
end,
|
end,
|
||||||
delete_auth = function(name)
|
delete_auth = function(name)
|
||||||
|
@ -1068,7 +1068,7 @@ core.register_chatcommand("last-login", {
|
|||||||
param = name
|
param = name
|
||||||
end
|
end
|
||||||
local pauth = core.get_auth_handler().get_auth(param)
|
local pauth = core.get_auth_handler().get_auth(param)
|
||||||
if pauth and pauth.last_login then
|
if pauth and pauth.last_login and pauth.last_login ~= -1 then
|
||||||
-- Time in UTC, ISO 8601 format
|
-- Time in UTC, ISO 8601 format
|
||||||
return true, "Last login time was " ..
|
return true, "Last login time was " ..
|
||||||
os.date("!%Y-%m-%dT%H:%M:%SZ", pauth.last_login)
|
os.date("!%Y-%m-%dT%H:%M:%SZ", pauth.last_login)
|
||||||
|
@ -70,3 +70,19 @@ core.setting_get = setting_proxy("get")
|
|||||||
core.setting_setbool = setting_proxy("set_bool")
|
core.setting_setbool = setting_proxy("set_bool")
|
||||||
core.setting_getbool = setting_proxy("get_bool")
|
core.setting_getbool = setting_proxy("get_bool")
|
||||||
core.setting_save = setting_proxy("write")
|
core.setting_save = setting_proxy("write")
|
||||||
|
|
||||||
|
--
|
||||||
|
-- core.register_on_auth_fail
|
||||||
|
--
|
||||||
|
|
||||||
|
function core.register_on_auth_fail(func)
|
||||||
|
core.log("deprecated", "core.register_on_auth_fail " ..
|
||||||
|
"is obsolete and should be replaced by " ..
|
||||||
|
"core.register_on_authplayer instead.")
|
||||||
|
|
||||||
|
core.register_on_authplayer(function (player_name, ip, is_success)
|
||||||
|
if not is_success then
|
||||||
|
func(player_name, ip)
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
end
|
||||||
|
@ -607,9 +607,9 @@ core.registered_on_item_eats, core.register_on_item_eat = make_registration()
|
|||||||
core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
|
core.registered_on_punchplayers, core.register_on_punchplayer = make_registration()
|
||||||
core.registered_on_priv_grant, core.register_on_priv_grant = make_registration()
|
core.registered_on_priv_grant, core.register_on_priv_grant = make_registration()
|
||||||
core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration()
|
core.registered_on_priv_revoke, core.register_on_priv_revoke = make_registration()
|
||||||
|
core.registered_on_authplayers, core.register_on_authplayer = make_registration()
|
||||||
core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_registration()
|
core.registered_can_bypass_userlimit, core.register_can_bypass_userlimit = make_registration()
|
||||||
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
|
core.registered_on_modchannel_message, core.register_on_modchannel_message = make_registration()
|
||||||
core.registered_on_auth_fail, core.register_on_auth_fail = make_registration()
|
|
||||||
core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration()
|
core.registered_on_player_inventory_actions, core.register_on_player_inventory_action = make_registration()
|
||||||
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
|
core.registered_allow_player_inventory_actions, core.register_allow_player_inventory_action = make_registration()
|
||||||
|
|
||||||
|
@ -4374,7 +4374,7 @@ Call these functions only at load time!
|
|||||||
* Called after generating a piece of world. Modifying nodes inside the area
|
* Called after generating a piece of world. Modifying nodes inside the area
|
||||||
is a bit faster than usually.
|
is a bit faster than usually.
|
||||||
* `minetest.register_on_newplayer(function(ObjectRef))`
|
* `minetest.register_on_newplayer(function(ObjectRef))`
|
||||||
* Called after a new player has been created
|
* Called when a new player enters the world for the first time
|
||||||
* `minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))`
|
* `minetest.register_on_punchplayer(function(player, hitter, time_from_last_punch, tool_capabilities, dir, damage))`
|
||||||
* Called when a player is punched
|
* Called when a player is punched
|
||||||
* Note: This callback is invoked even if the punched player is dead.
|
* Note: This callback is invoked even if the punched player is dead.
|
||||||
@ -4415,19 +4415,23 @@ Call these functions only at load time!
|
|||||||
* Called _before_ repositioning of player occurs
|
* Called _before_ repositioning of player occurs
|
||||||
* return true in func to disable regular player placement
|
* return true in func to disable regular player placement
|
||||||
* `minetest.register_on_prejoinplayer(function(name, ip))`
|
* `minetest.register_on_prejoinplayer(function(name, ip))`
|
||||||
* Called before a player joins the game
|
* Called when a client connects to the server, prior to authentication
|
||||||
* If it returns a string, the player is disconnected with that string as
|
* If it returns a string, the client is disconnected with that string as
|
||||||
reason.
|
reason.
|
||||||
* `minetest.register_on_joinplayer(function(ObjectRef))`
|
* `minetest.register_on_joinplayer(function(ObjectRef, last_login))`
|
||||||
* Called when a player joins the game
|
* Called when a player joins the game
|
||||||
|
* `last_login`: The timestamp of the previous login, or nil if player is new
|
||||||
* `minetest.register_on_leaveplayer(function(ObjectRef, timed_out))`
|
* `minetest.register_on_leaveplayer(function(ObjectRef, timed_out))`
|
||||||
* Called when a player leaves the game
|
* Called when a player leaves the game
|
||||||
* `timed_out`: True for timeout, false for other reasons.
|
* `timed_out`: True for timeout, false for other reasons.
|
||||||
|
* `minetest.register_on_authplayer(function(name, ip, is_success))`
|
||||||
|
* Called when a client attempts to log into an account.
|
||||||
|
* `name`: The name of the account being authenticated.
|
||||||
|
* `ip`: The IP address of the client
|
||||||
|
* `is_success`: Whether the client was successfully authenticated
|
||||||
|
* For newly registered accounts, `is_success` will always be true
|
||||||
* `minetest.register_on_auth_fail(function(name, ip))`
|
* `minetest.register_on_auth_fail(function(name, ip))`
|
||||||
* Called when a client attempts to log into an account but supplies the
|
* Deprecated: use `minetest.register_on_authplayer(name, ip, is_success)` instead.
|
||||||
wrong password.
|
|
||||||
* `ip`: The IP address of the client.
|
|
||||||
* `name`: The account the client attempted to log into.
|
|
||||||
* `minetest.register_on_cheat(function(ObjectRef, cheat))`
|
* `minetest.register_on_cheat(function(ObjectRef, cheat))`
|
||||||
* Called when a player cheats
|
* Called when a player cheats
|
||||||
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
|
* `cheat`: `{type=<cheat_type>}`, where `<cheat_type>` is one of:
|
||||||
|
@ -409,9 +409,12 @@ void Server::handleCommand_ClientReady(NetworkPacket* pkt)
|
|||||||
// (u16) 1 + std::string represents a pseudo vector serialization representation
|
// (u16) 1 + std::string represents a pseudo vector serialization representation
|
||||||
notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName());
|
notice_pkt << (u8) PLAYER_LIST_ADD << (u16) 1 << std::string(playersao->getPlayer()->getName());
|
||||||
m_clients.sendToAll(¬ice_pkt);
|
m_clients.sendToAll(¬ice_pkt);
|
||||||
|
|
||||||
m_clients.event(peer_id, CSE_SetClientReady);
|
m_clients.event(peer_id, CSE_SetClientReady);
|
||||||
m_script->on_joinplayer(playersao);
|
|
||||||
|
s64 last_login;
|
||||||
|
m_script->getAuth(playersao->getPlayer()->getName(), nullptr, nullptr, &last_login);
|
||||||
|
m_script->on_joinplayer(playersao, last_login);
|
||||||
|
|
||||||
// Send shutdown timer if shutdown has been scheduled
|
// Send shutdown timer if shutdown has been scheduled
|
||||||
if (m_shutdown_state.isTimerRunning()) {
|
if (m_shutdown_state.isTimerRunning()) {
|
||||||
SendChatMessage(peer_id, m_shutdown_state.getShutdownTimerMessage());
|
SendChatMessage(peer_id, m_shutdown_state.getShutdownTimerMessage());
|
||||||
@ -1512,6 +1515,7 @@ void Server::handleCommand_FirstSrp(NetworkPacket* pkt)
|
|||||||
|
|
||||||
initial_ver_key = encode_srp_verifier(verification_key, salt);
|
initial_ver_key = encode_srp_verifier(verification_key, salt);
|
||||||
m_script->createAuth(playername, initial_ver_key);
|
m_script->createAuth(playername, initial_ver_key);
|
||||||
|
m_script->on_authplayer(playername, addr_s, true);
|
||||||
|
|
||||||
acceptAuth(peer_id, false);
|
acceptAuth(peer_id, false);
|
||||||
} else {
|
} else {
|
||||||
@ -1648,24 +1652,25 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
|
|||||||
session_t peer_id = pkt->getPeerId();
|
session_t peer_id = pkt->getPeerId();
|
||||||
RemoteClient *client = getClient(peer_id, CS_Invalid);
|
RemoteClient *client = getClient(peer_id, CS_Invalid);
|
||||||
ClientState cstate = client->getState();
|
ClientState cstate = client->getState();
|
||||||
|
std::string addr_s = getPeerAddress(pkt->getPeerId()).serializeString();
|
||||||
|
std::string playername = client->getName();
|
||||||
|
|
||||||
bool wantSudo = (cstate == CS_Active);
|
bool wantSudo = (cstate == CS_Active);
|
||||||
|
|
||||||
verbosestream << "Server: Received TOCLIENT_SRP_BYTES_M." << std::endl;
|
verbosestream << "Server: Received TOCLIENT_SRP_BYTES_M." << std::endl;
|
||||||
|
|
||||||
if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
|
if (!((cstate == CS_HelloSent) || (cstate == CS_Active))) {
|
||||||
actionstream << "Server: got SRP _M packet in wrong state " << cstate <<
|
actionstream << "Server: got SRP _M packet in wrong state "
|
||||||
" from " << getPeerAddress(peer_id).serializeString() <<
|
<< cstate << " from " << addr_s
|
||||||
". Ignoring." << std::endl;
|
<< ". Ignoring." << std::endl;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->chosen_mech != AUTH_MECHANISM_SRP &&
|
if (client->chosen_mech != AUTH_MECHANISM_SRP &&
|
||||||
client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
|
client->chosen_mech != AUTH_MECHANISM_LEGACY_PASSWORD) {
|
||||||
actionstream << "Server: got SRP _M packet, while auth is going on "
|
actionstream << "Server: got SRP _M packet, while auth"
|
||||||
"with mech " << client->chosen_mech << " from " <<
|
<< "is going on with mech " << client->chosen_mech << " from "
|
||||||
getPeerAddress(peer_id).serializeString() <<
|
<< addr_s << " (wantSudo=" << wantSudo << "). Denying." << std::endl;
|
||||||
" (wantSudo=" << wantSudo << "). Denying." << std::endl;
|
|
||||||
if (wantSudo) {
|
if (wantSudo) {
|
||||||
DenySudoAccess(peer_id);
|
DenySudoAccess(peer_id);
|
||||||
return;
|
return;
|
||||||
@ -1680,9 +1685,8 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
|
|||||||
|
|
||||||
if (srp_verifier_get_session_key_length((SRPVerifier *) client->auth_data)
|
if (srp_verifier_get_session_key_length((SRPVerifier *) client->auth_data)
|
||||||
!= bytes_M.size()) {
|
!= bytes_M.size()) {
|
||||||
actionstream << "Server: User " << client->getName() << " at " <<
|
actionstream << "Server: User " << playername << " at " << addr_s
|
||||||
getPeerAddress(peer_id).serializeString() <<
|
<< " sent bytes_M with invalid length " << bytes_M.size() << std::endl;
|
||||||
" sent bytes_M with invalid length " << bytes_M.size() << std::endl;
|
|
||||||
DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
|
DenyAccess(peer_id, SERVER_ACCESSDENIED_UNEXPECTED_DATA);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1694,24 +1698,21 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
|
|||||||
|
|
||||||
if (!bytes_HAMK) {
|
if (!bytes_HAMK) {
|
||||||
if (wantSudo) {
|
if (wantSudo) {
|
||||||
actionstream << "Server: User " << client->getName() << " at " <<
|
actionstream << "Server: User " << playername << " at " << addr_s
|
||||||
getPeerAddress(peer_id).serializeString() <<
|
<< " tried to change their password, but supplied wrong"
|
||||||
" tried to change their password, but supplied wrong (SRP) "
|
<< " (SRP) password for authentication." << std::endl;
|
||||||
"password for authentication." << std::endl;
|
|
||||||
DenySudoAccess(peer_id);
|
DenySudoAccess(peer_id);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string ip = getPeerAddress(peer_id).serializeString();
|
actionstream << "Server: User " << playername << " at " << addr_s
|
||||||
actionstream << "Server: User " << client->getName() << " at " << ip <<
|
<< " supplied wrong password (auth mechanism: SRP)." << std::endl;
|
||||||
" supplied wrong password (auth mechanism: SRP)." << std::endl;
|
m_script->on_authplayer(playername, addr_s, false);
|
||||||
m_script->on_auth_failure(client->getName(), ip);
|
|
||||||
DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_PASSWORD);
|
DenyAccess(peer_id, SERVER_ACCESSDENIED_WRONG_PASSWORD);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (client->create_player_on_auth_success) {
|
if (client->create_player_on_auth_success) {
|
||||||
std::string playername = client->getName();
|
|
||||||
m_script->createAuth(playername, client->enc_pwd);
|
m_script->createAuth(playername, client->enc_pwd);
|
||||||
|
|
||||||
std::string checkpwd; // not used, but needed for passing something
|
std::string checkpwd; // not used, but needed for passing something
|
||||||
@ -1725,6 +1726,7 @@ void Server::handleCommand_SrpBytesM(NetworkPacket* pkt)
|
|||||||
client->create_player_on_auth_success = false;
|
client->create_player_on_auth_success = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
m_script->on_authplayer(playername, addr_s, true);
|
||||||
acceptAuth(peer_id, wantSudo);
|
acceptAuth(peer_id, wantSudo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,7 +147,7 @@ bool ScriptApiPlayer::can_bypass_userlimit(const std::string &name, const std::s
|
|||||||
return lua_toboolean(L, -1);
|
return lua_toboolean(L, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
|
void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player, s64 last_login)
|
||||||
{
|
{
|
||||||
SCRIPTAPI_PRECHECKHEADER
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
@ -156,7 +156,11 @@ void ScriptApiPlayer::on_joinplayer(ServerActiveObject *player)
|
|||||||
lua_getfield(L, -1, "registered_on_joinplayers");
|
lua_getfield(L, -1, "registered_on_joinplayers");
|
||||||
// Call callbacks
|
// Call callbacks
|
||||||
objectrefGetOrCreate(L, player);
|
objectrefGetOrCreate(L, player);
|
||||||
runCallbacks(1, RUN_CALLBACKS_MODE_FIRST);
|
if (last_login != -1)
|
||||||
|
lua_pushinteger(L, last_login);
|
||||||
|
else
|
||||||
|
lua_pushnil(L);
|
||||||
|
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player,
|
void ScriptApiPlayer::on_leaveplayer(ServerActiveObject *player,
|
||||||
@ -216,16 +220,19 @@ void ScriptApiPlayer::on_playerReceiveFields(ServerActiveObject *player,
|
|||||||
runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
|
runCallbacks(3, RUN_CALLBACKS_MODE_OR_SC);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptApiPlayer::on_auth_failure(const std::string &name, const std::string &ip)
|
void ScriptApiPlayer::on_authplayer(const std::string &name, const std::string &ip, bool is_success)
|
||||||
{
|
{
|
||||||
SCRIPTAPI_PRECHECKHEADER
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
// Get core.registered_on_auth_failure
|
// Get core.registered_on_authplayers
|
||||||
lua_getglobal(L, "core");
|
lua_getglobal(L, "core");
|
||||||
lua_getfield(L, -1, "registered_on_auth_fail");
|
lua_getfield(L, -1, "registered_on_authplayers");
|
||||||
|
|
||||||
|
// Call callbacks
|
||||||
lua_pushstring(L, name.c_str());
|
lua_pushstring(L, name.c_str());
|
||||||
lua_pushstring(L, ip.c_str());
|
lua_pushstring(L, ip.c_str());
|
||||||
runCallbacks(2, RUN_CALLBACKS_MODE_FIRST);
|
lua_pushboolean(L, is_success);
|
||||||
|
runCallbacks(3, RUN_CALLBACKS_MODE_FIRST);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ScriptApiPlayer::pushMoveArguments(
|
void ScriptApiPlayer::pushMoveArguments(
|
||||||
|
@ -41,7 +41,7 @@ public:
|
|||||||
bool on_prejoinplayer(const std::string &name, const std::string &ip,
|
bool on_prejoinplayer(const std::string &name, const std::string &ip,
|
||||||
std::string *reason);
|
std::string *reason);
|
||||||
bool can_bypass_userlimit(const std::string &name, const std::string &ip);
|
bool can_bypass_userlimit(const std::string &name, const std::string &ip);
|
||||||
void on_joinplayer(ServerActiveObject *player);
|
void on_joinplayer(ServerActiveObject *player, s64 last_login);
|
||||||
void on_leaveplayer(ServerActiveObject *player, bool timeout);
|
void on_leaveplayer(ServerActiveObject *player, bool timeout);
|
||||||
void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
|
void on_cheat(ServerActiveObject *player, const std::string &cheat_type);
|
||||||
bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
|
bool on_punchplayer(ServerActiveObject *player, ServerActiveObject *hitter,
|
||||||
@ -51,7 +51,7 @@ public:
|
|||||||
const PlayerHPChangeReason &reason);
|
const PlayerHPChangeReason &reason);
|
||||||
void on_playerReceiveFields(ServerActiveObject *player,
|
void on_playerReceiveFields(ServerActiveObject *player,
|
||||||
const std::string &formname, const StringMap &fields);
|
const std::string &formname, const StringMap &fields);
|
||||||
void on_auth_failure(const std::string &name, const std::string &ip);
|
void on_authplayer(const std::string &name, const std::string &ip, bool is_success);
|
||||||
|
|
||||||
// Player inventory callbacks
|
// Player inventory callbacks
|
||||||
// Return number of accepted items to be moved
|
// Return number of accepted items to be moved
|
||||||
|
@ -23,7 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
|
|||||||
|
|
||||||
bool ScriptApiServer::getAuth(const std::string &playername,
|
bool ScriptApiServer::getAuth(const std::string &playername,
|
||||||
std::string *dst_password,
|
std::string *dst_password,
|
||||||
std::set<std::string> *dst_privs)
|
std::set<std::string> *dst_privs,
|
||||||
|
s64 *dst_last_login)
|
||||||
{
|
{
|
||||||
SCRIPTAPI_PRECHECKHEADER
|
SCRIPTAPI_PRECHECKHEADER
|
||||||
|
|
||||||
@ -43,8 +44,7 @@ bool ScriptApiServer::getAuth(const std::string &playername,
|
|||||||
luaL_checktype(L, -1, LUA_TTABLE);
|
luaL_checktype(L, -1, LUA_TTABLE);
|
||||||
|
|
||||||
std::string password;
|
std::string password;
|
||||||
bool found = getstringfield(L, -1, "password", password);
|
if (!getstringfield(L, -1, "password", password))
|
||||||
if (!found)
|
|
||||||
throw LuaError("Authentication handler didn't return password");
|
throw LuaError("Authentication handler didn't return password");
|
||||||
if (dst_password)
|
if (dst_password)
|
||||||
*dst_password = password;
|
*dst_password = password;
|
||||||
@ -54,7 +54,13 @@ bool ScriptApiServer::getAuth(const std::string &playername,
|
|||||||
throw LuaError("Authentication handler didn't return privilege table");
|
throw LuaError("Authentication handler didn't return privilege table");
|
||||||
if (dst_privs)
|
if (dst_privs)
|
||||||
readPrivileges(-1, *dst_privs);
|
readPrivileges(-1, *dst_privs);
|
||||||
lua_pop(L, 1);
|
lua_pop(L, 1); // Remove key from privs table
|
||||||
|
|
||||||
|
s64 last_login;
|
||||||
|
if(!getintfield(L, -1, "last_login", last_login))
|
||||||
|
throw LuaError("Authentication handler didn't return last_login");
|
||||||
|
if (dst_last_login)
|
||||||
|
*dst_last_login = (s64)last_login;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ public:
|
|||||||
/* auth */
|
/* auth */
|
||||||
bool getAuth(const std::string &playername,
|
bool getAuth(const std::string &playername,
|
||||||
std::string *dst_password,
|
std::string *dst_password,
|
||||||
std::set<std::string> *dst_privs);
|
std::set<std::string> *dst_privs,
|
||||||
|
s64 *dst_last_login = nullptr);
|
||||||
void createAuth(const std::string &playername,
|
void createAuth(const std::string &playername,
|
||||||
const std::string &password);
|
const std::string &password);
|
||||||
bool setPassword(const std::string &playername,
|
bool setPassword(const std::string &playername,
|
||||||
|
Loading…
Reference in New Issue
Block a user