From: Ciaran Gultnieks Date: Mon, 16 May 2011 09:41:19 +0000 (+0100) Subject: Improved server commands and added player permissions. X-Git-Url: http://81.2.79.47:8989/gitweb/?a=commitdiff_plain;h=248d7c8469f8cb37406ea0ce56d0945e38334cfb;p=zefram%2Fminetest%2Fminetest_engine.git Improved server commands and added player permissions. --HG-- extra : rebase_source : 178fe08f10b7de3ebaba088bd24faad795114216 --- diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 8e6f5430..42260b3a 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -69,6 +69,7 @@ set(common_SRCS connection.cpp environment.cpp server.cpp + servercommand.cpp socket.cpp mapblock.cpp mapsector.cpp diff --git a/src/player.cpp b/src/player.cpp index 64780de7..a6ddeee6 100644 --- a/src/player.cpp +++ b/src/player.cpp @@ -34,7 +34,8 @@ Player::Player(): m_pitch(0), m_yaw(0), m_speed(0,0,0), - m_position(0,0,0) + m_position(0,0,0), + privs(PRIV_DEFAULT) { updateName(""); resetInventory(); @@ -100,6 +101,7 @@ void Player::serialize(std::ostream &os) args.setV3F("position", m_position); args.setBool("craftresult_is_preview", craftresult_is_preview); args.setS32("hp", hp); + args.setU64("privs", privs); args.writeLines(os); @@ -141,6 +143,11 @@ void Player::deSerialize(std::istream &is) }catch(SettingNotFoundException &e){ hp = 20; } + try{ + privs = args.getU64("privs"); + }catch(SettingNotFoundException &e){ + privs = PRIV_DEFAULT; + } inventory.deSerialize(is); } diff --git a/src/player.h b/src/player.h index f70b52fe..778bb54b 100644 --- a/src/player.h +++ b/src/player.h @@ -28,11 +28,29 @@ with this program; if not, write to the Free Software Foundation, Inc., #define PLAYERNAME_ALLOWED_CHARS "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.," +// Player privileges. These form a bitmask stored in the privs field +// of the player, and define things they're allowed to do. See also +// the static methods Player::privsToString and stringToPrivs that +// convert these to human-readable form. +const u64 PRIV_BUILD = 1; // Can build - i.e. modify the world + // (not enforced yet) +const u64 PRIV_TELEPORT = 2; // Can teleport +const u64 PRIV_SETTIME = 4; // Can set the time +const u64 PRIV_PRIVS = 8; // Can grant and revoke privileges +const u64 PRIV_SERVER = 16; // Can manage the server (e.g. shutodwn ,settings) + +const u64 PRIV_DEFAULT = PRIV_BUILD; +const u64 PRIV_ALL = 0x7FFFFFFFFFFFFFFFULL; +const u64 PRIV_INVALID = 0x8000000000000000ULL; + + class Map; class Player { public: + + Player(); virtual ~Player(); @@ -123,6 +141,9 @@ public: u16 hp; + // Player's privileges - a bitmaps of PRIV_xxxx. + u64 privs; + u16 peer_id; protected: @@ -131,6 +152,57 @@ protected: f32 m_yaw; v3f m_speed; v3f m_position; + +public: + + // Converst a prvileges value into a human-readable string, + // with each component separated by a comma. + static std::wstring privsToString(u64 privs) + { + std::wostringstream os(std::ios_base::binary); + if(privs & PRIV_BUILD) + os< pr; + pr=str_split(str, ','); + for(std::vector::iterator i = pr.begin(); + i != pr.end(); ++i) + { + if(*i == L"build") + privs |= PRIV_BUILD; + else if(*i == L"teleport") + privs |= PRIV_TELEPORT; + else if(*i == L"settime") + privs |= PRIV_SETTIME; + else if(*i == L"privs") + privs |= PRIV_PRIVS; + else + return PRIV_INVALID; + } + return privs; + } + }; /* diff --git a/src/server.cpp b/src/server.cpp index b5a38aa0..f77b4f3c 100644 --- a/src/server.cpp +++ b/src/server.cpp @@ -29,6 +29,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include "materials.h" #include "mineral.h" #include "config.h" +#include "servercommand.h" #define BLOCK_EMERGE_FLAG_FROMDISK (1<<0) @@ -1994,6 +1995,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 13) return; + if((player->privs & PRIV_BUILD) == 0) + return; + /* [0] u16 command [2] u8 button (0=left, 1=right) @@ -2075,6 +2079,9 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) if(datasize < 7) return; + if((player->privs & PRIV_BUILD) == 0) + return; + /* length: 7 [0] u16 command @@ -2167,6 +2174,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) { if(datasize < 17) return; + if((player->privs & PRIV_BUILD) == 0) + return; /* length: 17 [0] u16 command @@ -2615,6 +2624,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) #endif else if(command == TOSERVER_SIGNTEXT) { + if((player->privs & PRIV_BUILD) == 0) + return; /* u16 command v3s16 blockpos @@ -2672,6 +2683,8 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) } else if(command == TOSERVER_SIGNNODETEXT) { + if((player->privs & PRIV_BUILD) == 0) + return; /* u16 command v3s16 p @@ -2853,71 +2866,19 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id) line += L"Server: "; message = message.substr(commandprefix.size()); - // Get player name as narrow string - std::string name_s = player->getName(); - // Convert message to narrow string - std::string message_s = wide_to_narrow(message); - // Operator is the single name defined in config. - std::string operator_name = g_settings.get("name"); - bool is_operator = (operator_name != "" && - wide_to_narrow(name) == operator_name); - bool valid_command = false; - if(message_s == "help") - { - line += L"-!- Available commands: "; - line += L"status "; - if(is_operator) - { - line += L"shutdown setting time "; - } - else - { - } - send_to_sender = true; - valid_command = true; - } - else if(message_s == "status") - { - line = getStatusString(); - send_to_sender = true; - valid_command = true; - } - else if(is_operator) - { - if(message_s == "shutdown") - { - dstream<flags & 1; + send_to_others = ctx->flags & 2; + delete ctx; + } else { diff --git a/src/server.h b/src/server.h index 4603f98e..d8b47aef 100644 --- a/src/server.h +++ b/src/server.h @@ -387,6 +387,12 @@ public: return time_to_daynight_ratio(m_time_of_day.get()); } + void setTimeOfDay(u32 time) + { + m_time_of_day.set(time); + m_time_of_day_send_timer = 0; + } + bool getShutdownRequested() { return m_shutdown_requested.get(); @@ -405,6 +411,19 @@ public: Inventory* getInventory(InventoryContext *c, std::string id); void inventoryModified(InventoryContext *c, std::string id); + // Connection must be locked when called + std::wstring getStatusString(); + + void requestShutdown(void) + { + m_shutdown_requested.set(true); + } + + + // Envlock and conlock should be locked when calling this + void SendMovePlayer(Player *player); + + private: // Virtual methods from con::PeerHandler. @@ -429,7 +448,6 @@ private: void SendChatMessage(u16 peer_id, const std::wstring &message); void BroadcastChatMessage(const std::wstring &message); void SendPlayerHP(Player *player); - void SendMovePlayer(Player *player); /* Send a node removal/addition event to all clients except ignore_id. Additionally, if far_players!=NULL, players further away than @@ -455,9 +473,6 @@ private: // When called, connection mutex should be locked RemoteClient* getClient(u16 peer_id); - // Connection must be locked when called - std::wstring getStatusString(); - /* Get a player from memory or creates one. If player is already connected, return NULL diff --git a/src/servercommand.cpp b/src/servercommand.cpp new file mode 100644 index 00000000..fa841a1b --- /dev/null +++ b/src/servercommand.cpp @@ -0,0 +1,233 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola +Copyright (C) 2011 Ciaran Gultnieks + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + + +#include "servercommand.h" +#include "utility.h" + +// Process a command sent from a client. The environment and connection +// should be locked when this is called. +// Returns a response message, to be dealt with according to the flags set +// in the context. +std::wstring ServerCommand::processCommand(ServerCommandContext *ctx) +{ + + std::wostringstream os(std::ios_base::binary); + ctx->flags = 1; // Default, unless we change it. + + u64 privs = ctx->player->privs; + + if(ctx->parms.size() == 0 || ctx->parms[0] == L"help") + { + os<parms[0] == L"status") + { + cmd_status(os, ctx); + } + else if(ctx->parms[0] == L"privs") + { + cmd_privs(os, ctx); + } + else if(ctx->parms[0] == L"grant" || ctx->parms[0] == L"revoke") + { + cmd_grantrevoke(os, ctx); + } + else if(ctx->parms[0] == L"time") + { + cmd_time(os, ctx); + } + else if(ctx->parms[0] == L"shutdown") + { + cmd_shutdown(os, ctx); + } + else if(ctx->parms[0] == L"setting") + { + cmd_setting(os, ctx); + } + else if(ctx->parms[0] == L"teleport") + { + cmd_teleport(os, ctx); + } + else + { + os<parms[0]; + } + return os.str(); +} + +void ServerCommand::cmd_status(std::wostringstream &os, + ServerCommandContext *ctx) +{ + os<server->getStatusString(); +} + +void ServerCommand::cmd_privs(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if(ctx->parms.size() == 1) + { + os<player->privs); + return; + } + + if((ctx->player->privs & PRIV_PRIVS) == 0) + { + os<env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str()); + if(tp == NULL) + { + os<privs); +} + +void ServerCommand::cmd_grantrevoke(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if(ctx->parms.size() != 3) + { + os<player->privs & PRIV_PRIVS) == 0) + { + os<parms[2]); + if(newprivs == PRIV_INVALID) + { + os<env->getPlayer(wide_to_narrow(ctx->parms[1]).c_str()); + if(tp == NULL) + { + os<parms[0] == L"grant") + tp->privs |= newprivs; + else + tp->privs &= ~newprivs; + + os<privs); +} + +void ServerCommand::cmd_time(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if(ctx->parms.size() != 2) + { + os<player->privs & PRIV_SETTIME) ==0) + { + os<parms[1])); + ctx->server->setTimeOfDay(time); + os<player->privs & PRIV_SERVER) ==0) + { + os<server->requestShutdown(); + + os<flags |= 2; +} + +void ServerCommand::cmd_setting(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if((ctx->player->privs & PRIV_SERVER) ==0) + { + os<parms[1] + L" = " + ctx->parms[2]); + g_settings.parseConfigLine(confline); + os<< L"-!- Setting changed."; +} + +void ServerCommand::cmd_teleport(std::wostringstream &os, + ServerCommandContext *ctx) +{ + if((ctx->player->privs & PRIV_TELEPORT) ==0) + { + os<parms.size() != 2) + { + os< coords = str_split(ctx->parms[1], L','); + if(coords.size() != 3) + { + os<player->setPosition(dest); + ctx->server->SendMovePlayer(ctx->player); + + os<< L"-!- Teleported."; +} + diff --git a/src/servercommand.h b/src/servercommand.h new file mode 100644 index 00000000..01efcae0 --- /dev/null +++ b/src/servercommand.h @@ -0,0 +1,76 @@ +/* +Minetest-c55 +Copyright (C) 2010-2011 celeron55, Perttu Ahola +Copyright (C) 2011 Ciaran Gultnieks + +This program is free software; you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation; either version 2 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License along +with this program; if not, write to the Free Software Foundation, Inc., +51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +*/ + +#ifndef SERVERCOMMAND_HEADER +#define SERVERCOMMAND_HEADER + +#include +#include +#include "common_irrlicht.h" +#include "player.h" +#include "server.h" + +struct ServerCommandContext +{ + + std::vector parms; + Server* server; + ServerEnvironment *env; + Player* player; + u32 flags; + + ServerCommandContext( + std::vector parms, + Server* server, + ServerEnvironment *env, + Player* player) + : parms(parms), server(server), env(env), player(player) + { + } + +}; + +class ServerCommand +{ +public: + + static std::wstring processCommand(ServerCommandContext *ctx); + +private: + + static void cmd_status(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_privs(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_grantrevoke(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_time(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_shutdown(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_setting(std::wostringstream &os, + ServerCommandContext *ctx); + static void cmd_teleport(std::wostringstream &os, + ServerCommandContext *ctx); +}; + +#endif + + diff --git a/src/utility.h b/src/utility.h index 12d732be..326ebf16 100644 --- a/src/utility.h +++ b/src/utility.h @@ -24,6 +24,7 @@ with this program; if not, write to the Free Software Foundation, Inc., #include #include #include +#include #include #include #include @@ -731,6 +732,19 @@ inline std::string wide_to_narrow(const std::wstring& wcs) return *mbs; } +// Split a string using the given delimiter. Returns a vector containing +// the component parts. +inline std::vector str_split(const std::wstring &str, wchar_t delimiter) +{ + std::vector parts; + std::wstringstream sstr(str); + std::wstring part; + while(std::getline(sstr, part, delimiter)) + parts.push_back(part); + return parts; +} + + /* See test.cpp for example cases. wraps degrees to the range of -360...360 @@ -791,6 +805,11 @@ inline s32 stoi(std::string s) return atoi(s.c_str()); } +inline s32 stoi(std::wstring s) +{ + return atoi(wide_to_narrow(s).c_str()); +} + inline float stof(std::string s) { float f;