Added the ability to change your password (via pause menu)
authorCiaran Gultnieks <ciaran@ciarang.com>
Sun, 22 May 2011 20:09:12 +0000 (21:09 +0100)
committerCiaran Gultnieks <ciaran@ciarang.com>
Sun, 22 May 2011 20:09:12 +0000 (21:09 +0100)
--HG--
extra : rebase_source : e8ec407f60711d42d33be4811b2880088f617b5b

14 files changed:
src/CMakeLists.txt
src/client.cpp
src/client.h
src/clientserver.h
src/game.cpp
src/guiPasswordChange.cpp [new file with mode: 0644]
src/guiPasswordChange.h [new file with mode: 0644]
src/guiPauseMenu.cpp
src/guiPauseMenu.h
src/main.cpp
src/main.h
src/server.cpp
src/utility.cpp
src/utility.h

index 58596a10164f46e9237f3c1b06488e47c2371119..49982d310e62565989a56b628e022c0ed849a013 100644 (file)
@@ -77,6 +77,8 @@ set(common_SRCS
        player.cpp
        utility.cpp
        test.cpp
+       sha1.cpp
+       base64.cpp
 )
 
 # Client sources
@@ -91,12 +93,11 @@ set(minetest_SRCS
        guiTextInputMenu.cpp
        guiInventoryMenu.cpp
        guiPauseMenu.cpp
+       guiPasswordChange.cpp
        client.cpp
        tile.cpp
        game.cpp
        main.cpp
-       sha1.cpp
-       base64.cpp
 )
 
 # Server sources
index c85d6e9e23430cf49aa410230c202179142dc6f8..5869dc77bbab1714d1e12d6395b890811578327a 100644 (file)
@@ -1602,6 +1602,43 @@ void Client::sendChatMessage(const std::wstring &message)
        Send(0, data, true);
 }
 
+void Client::sendChangePassword(const std::wstring oldpassword,
+               const std::wstring newpassword)
+{
+       Player *player = m_env.getLocalPlayer();
+       if(player == NULL)
+               return;
+
+       std::string playername = player->getName();
+       std::string oldpwd = translatePassword(playername, oldpassword);
+       std::string newpwd = translatePassword(playername, newpassword);
+
+       std::ostringstream os(std::ios_base::binary);
+       u8 buf[2+PASSWORD_SIZE*2];
+       /*
+               [0] u16 TOSERVER_PASSWORD
+               [2] u8[28] old password
+               [30] u8[28] new password
+       */
+
+       writeU16(buf, TOSERVER_PASSWORD);
+       for(u32 i=0;i<PASSWORD_SIZE-1;i++)
+       {
+               buf[2+i] = i<oldpwd.length()?oldpwd[i]:0;
+               buf[30+i] = i<newpwd.length()?newpwd[i]:0;
+       }
+       buf[2+PASSWORD_SIZE-1] = 0;
+       buf[30+PASSWORD_SIZE-1] = 0;
+       os.write((char*)buf, 2+PASSWORD_SIZE*2);
+
+       // Make data buffer
+       std::string s = os.str();
+       SharedBuffer<u8> data((u8*)s.c_str(), s.size());
+       // Send as reliable
+       Send(0, data, true);
+}
+
+
 void Client::sendDamage(u8 damage)
 {
        DSTACK(__FUNCTION_NAME);
index 222f83ab739615c24e7e0d0ca05651db4cbd04a9..f661838cee216ce5466d352845558721f41085a4 100644 (file)
@@ -255,6 +255,8 @@ public:
        void sendSignNodeText(v3s16 p, std::string text);
        void sendInventoryAction(InventoryAction *a);
        void sendChatMessage(const std::wstring &message);
+       void sendChangePassword(const std::wstring oldpassword,
+               const std::wstring newpassword);
        void sendDamage(u8 damage);
        
        // locks envlock
index a64a11f08a858d0f387036bce21fec32c07458cd..256aed362779b0da8ae5176359d724d61ff86c68 100644 (file)
@@ -285,6 +285,16 @@ enum ToServerCommand
                u16 command
                u8 amount
        */
+
+       TOSERVER_PASSWORD=0x36,
+       /*
+               Sent to change password.
+
+               [0] u16 TOSERVER_PASSWORD
+               [2] u8[28] old password
+               [30] u8[28] new password
+       */
+
 };
 
 inline SharedBuffer<u8> makePacket_TOCLIENT_TIME_OF_DAY(u16 time)
index 99e08b7bfb5999d6dadfd9642f78efe19b943b98..e82e4cd8e59451fafe9810fe2a6431b507ff5187 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "client.h"
 #include "server.h"
 #include "guiPauseMenu.h"
+#include "guiPasswordChange.h"
 #include "guiInventoryMenu.h"
 #include "guiTextInputMenu.h"
 #include "guiFurnaceMenu.h"
@@ -912,6 +913,13 @@ void the_game(
                        break;
                }
 
+               if(g_gamecallback->changepassword_requested)
+               {
+                       (new GUIPasswordChange(guienv, guiroot, -1,
+                               &g_menumgr, &client))->drop();
+                       g_gamecallback->changepassword_requested = false;
+               }
+
                /*
                        Process TextureSource's queue
                */
diff --git a/src/guiPasswordChange.cpp b/src/guiPasswordChange.cpp
new file mode 100644 (file)
index 0000000..98b11b4
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+Minetest-c55
+Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+
+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 "guiPasswordChange.h"
+#include "debug.h"
+#include "serialization.h"
+#include <string>
+
+const int ID_oldPassword = 256;
+const int ID_newPassword1 = 257;
+const int ID_newPassword2 = 258;
+const int ID_change = 259;
+const int ID_message = 260;
+
+GUIPasswordChange::GUIPasswordChange(gui::IGUIEnvironment* env,
+               gui::IGUIElement* parent, s32 id,
+               IMenuManager *menumgr,
+               Client* client
+):
+       GUIModalMenu(env, parent, id, menumgr),
+       m_client(client)
+{
+}
+
+GUIPasswordChange::~GUIPasswordChange()
+{
+       removeChildren();
+}
+
+void GUIPasswordChange::removeChildren()
+{
+       {
+               gui::IGUIElement *e = getElementFromId(ID_oldPassword);
+               if(e != NULL)
+                       e->remove();
+       }
+       {
+               gui::IGUIElement *e = getElementFromId(ID_newPassword1);
+               if(e != NULL)
+                       e->remove();
+       }
+       {
+               gui::IGUIElement *e = getElementFromId(ID_newPassword2);
+               if(e != NULL)
+                       e->remove();
+       }
+       {
+               gui::IGUIElement *e = getElementFromId(ID_change);
+               if(e != NULL)
+                       e->remove();
+       }
+}
+
+void GUIPasswordChange::regenerateGui(v2u32 screensize)
+{
+       /*
+               Remove stuff
+       */
+       removeChildren();
+       
+       /*
+               Calculate new sizes and positions
+       */
+       core::rect<s32> rect(
+                       screensize.X/2 - 580/2,
+                       screensize.Y/2 - 300/2,
+                       screensize.X/2 + 580/2,
+                       screensize.Y/2 + 300/2
+       );
+       
+       DesiredRect = rect;
+       recalculateAbsolutePosition(false);
+
+       v2s32 size = rect.getSize();
+       v2s32 topleft_client(40, 0);
+       v2s32 size_client = size - v2s32(40, 0);
+
+       /*
+               Add stuff
+       */
+       s32 ypos = 50;
+       {
+               core::rect<s32> rect(0, 0, 110, 20);
+               rect += topleft_client + v2s32(35, ypos+6);
+               const wchar_t *text = L"Old Password";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+       }
+       {
+               core::rect<s32> rect(0, 0, 230, 30);
+               rect += topleft_client + v2s32(160, ypos);
+               gui::IGUIEditBox *e = 
+               Environment->addEditBox(L"", rect, true, this, ID_oldPassword);
+               Environment->setFocus(e);
+               e->setPasswordBox(true);
+       }
+       ypos += 50;
+       {
+               core::rect<s32> rect(0, 0, 110, 20);
+               rect += topleft_client + v2s32(35, ypos+6);
+               const wchar_t *text = L"New Password";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+       }
+       {
+               core::rect<s32> rect(0, 0, 230, 30);
+               rect += topleft_client + v2s32(160, ypos);
+               gui::IGUIEditBox *e = 
+               Environment->addEditBox(L"", rect, true, this, ID_newPassword1);
+               e->setPasswordBox(true);
+       }
+       ypos += 50;
+       {
+               core::rect<s32> rect(0, 0, 110, 20);
+               rect += topleft_client + v2s32(35, ypos+6);
+               const wchar_t *text = L"Confirm Password";
+               Environment->addStaticText(text, rect, false, true, this, -1);
+       }
+       {
+               core::rect<s32> rect(0, 0, 230, 30);
+               rect += topleft_client + v2s32(160, ypos);
+               gui::IGUIEditBox *e = 
+               Environment->addEditBox(L"", rect, true, this, ID_newPassword2);
+               e->setPasswordBox(true);
+       }
+
+       ypos += 50;
+       {
+               core::rect<s32> rect(0, 0, 140, 30);
+               rect = rect + v2s32(size.X/2-140/2, ypos);
+               Environment->addButton(rect, this, ID_change, L"Change");
+       }
+
+       ypos += 50;
+       {
+               core::rect<s32> rect(0, 0, 300, 20);
+               rect += topleft_client + v2s32(35, ypos);
+               const wchar_t *text = L"Passwords do not match!";
+               IGUIElement *e = 
+               Environment->addStaticText(text, rect, false, true, this, ID_message);
+               e->setVisible(false);
+       }
+
+}
+
+void GUIPasswordChange::drawMenu()
+{
+       gui::IGUISkin* skin = Environment->getSkin();
+       if (!skin)
+               return;
+       video::IVideoDriver* driver = Environment->getVideoDriver();
+       
+       video::SColor bgcolor(140,0,0,0);
+       driver->draw2DRectangle(bgcolor, AbsoluteRect, &AbsoluteClippingRect);
+
+       gui::IGUIElement::draw();
+}
+
+bool GUIPasswordChange::acceptInput()
+{
+               std::wstring oldpass;
+               std::wstring newpass;
+               gui::IGUIElement *e;
+               e = getElementFromId(ID_oldPassword);
+               if(e != NULL)
+                       oldpass = e->getText();
+               e = getElementFromId(ID_newPassword1);
+               if(e != NULL)
+                       newpass = e->getText();
+               e = getElementFromId(ID_newPassword2);
+               if(e != NULL && newpass != e->getText())
+               {
+                       e = getElementFromId(ID_message);
+                       if(e != NULL)
+                               e->setVisible(true);
+                       return false;
+               }
+               m_client->sendChangePassword(oldpass, newpass);
+               return true;
+}
+
+bool GUIPasswordChange::OnEvent(const SEvent& event)
+{
+       if(event.EventType==EET_KEY_INPUT_EVENT)
+       {
+               if(event.KeyInput.Key==KEY_ESCAPE && event.KeyInput.PressedDown)
+               {
+                       quitMenu();
+                       return true;
+               }
+               if(event.KeyInput.Key==KEY_RETURN && event.KeyInput.PressedDown)
+               {
+                       if(acceptInput())
+                               quitMenu();
+                       return true;
+               }
+       }
+       if(event.EventType==EET_GUI_EVENT)
+       {
+               if(event.GUIEvent.EventType==gui::EGET_ELEMENT_FOCUS_LOST
+                               && isVisible())
+               {
+                       if(!canTakeFocus(event.GUIEvent.Element))
+                       {
+                               dstream<<"GUIPasswordChange: Not allowing focus change."
+                                               <<std::endl;
+                               // Returning true disables focus change
+                               return true;
+                       }
+               }
+               if(event.GUIEvent.EventType==gui::EGET_BUTTON_CLICKED)
+               {
+                       switch(event.GUIEvent.Caller->getID())
+                       {
+                       case ID_change:
+                               if(acceptInput())
+                                       quitMenu();
+                               return true;
+                       }
+               }
+               if(event.GUIEvent.EventType==gui::EGET_EDITBOX_ENTER)
+               {
+                       switch(event.GUIEvent.Caller->getID())
+                       {
+                       case ID_oldPassword:
+                       case ID_newPassword1:
+                       case ID_newPassword2:
+                               if(acceptInput())
+                                       quitMenu();
+                               return true;
+                       }
+               }
+       }
+
+       return Parent ? Parent->OnEvent(event) : false;
+}
+
diff --git a/src/guiPasswordChange.h b/src/guiPasswordChange.h
new file mode 100644 (file)
index 0000000..defac31
--- /dev/null
@@ -0,0 +1,57 @@
+/*
+Minetest-c55
+Copyright (C) 2010-11 celeron55, Perttu Ahola <celeron55@gmail.com>
+Copyright (C) 2011 Ciaran Gultnieks <ciaran@ciarang.com>
+
+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 GUIPASSWORDCHANGE_HEADER
+#define GUIPASSWORDCHANGE_HEADER
+
+#include "common_irrlicht.h"
+#include "modalMenu.h"
+#include "utility.h"
+#include "client.h"
+#include <string>
+
+class GUIPasswordChange : public GUIModalMenu
+{
+public:
+       GUIPasswordChange(gui::IGUIEnvironment* env,
+                       gui::IGUIElement* parent, s32 id,
+                       IMenuManager *menumgr,
+                       Client* client);
+       ~GUIPasswordChange();
+       
+       void removeChildren();
+       /*
+               Remove and re-add (or reposition) stuff
+       */
+       void regenerateGui(v2u32 screensize);
+
+       void drawMenu();
+
+       bool acceptInput();
+
+       bool OnEvent(const SEvent& event);
+       
+private:
+       Client* m_client;
+
+};
+
+#endif
+
index 2d42fdb77dec4189933ed5de7f3fd7f1a2043277..d32d1a10b375024d48fd9de457c695ef3956b110 100644 (file)
@@ -22,6 +22,7 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 #include "serialization.h"\r
 #include "porting.h"\r
 #include "config.h"\r
+#include "main.h"\r
 \r
 GUIPauseMenu::GUIPauseMenu(gui::IGUIEnvironment* env,\r
                gui::IGUIElement* parent, s32 id,\r
@@ -64,6 +65,11 @@ void GUIPauseMenu::removeChildren()
                if(e != NULL)\r
                        e->remove();\r
        }\r
+       {\r
+               gui::IGUIElement *e = getElementFromId(261);\r
+               if(e != NULL)\r
+                       e->remove();\r
+       }\r
 }\r
 \r
 void GUIPauseMenu::regenerateGui(v2u32 screensize)\r
@@ -91,21 +97,34 @@ void GUIPauseMenu::regenerateGui(v2u32 screensize)
        /*\r
                Add stuff\r
        */\r
+       const s32 btn_height = 30;\r
+       const s32 btn_gap = 20;\r
+       const s32 btn_num = 4;\r
+       s32 btn_y = size.Y/2-((btn_num*btn_height+(btn_num-1)*btn_gap))/2;\r
        {\r
-               core::rect<s32> rect(0, 0, 140, 30);\r
-               rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2-50);\r
+               core::rect<s32> rect(0, 0, 140, btn_height);\r
+               rect = rect + v2s32(size.X/2-140/2, btn_y);\r
                Environment->addButton(rect, this, 256, L"Continue");\r
        }\r
+       btn_y += btn_height + btn_gap;\r
+       {\r
+               core::rect<s32> rect(0, 0, 140, btn_height);\r
+               rect = rect + v2s32(size.X/2-140/2, btn_y);\r
+               Environment->addButton(rect, this, 261, L"Change Password");\r
+       }\r
+       btn_y += btn_height + btn_gap;\r
        {\r
-               core::rect<s32> rect(0, 0, 140, 30);\r
-               rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+0);\r
+               core::rect<s32> rect(0, 0, 140, btn_height);\r
+               rect = rect + v2s32(size.X/2-140/2, btn_y);\r
                Environment->addButton(rect, this, 260, L"Disconnect");\r
        }\r
+       btn_y += btn_height + btn_gap;\r
        {\r
-               core::rect<s32> rect(0, 0, 140, 30);\r
-               rect = rect + v2s32(size.X/2-140/2, size.Y/2-30/2+50);\r
+               core::rect<s32> rect(0, 0, 140, btn_height);\r
+               rect = rect + v2s32(size.X/2-140/2, btn_y);\r
                Environment->addButton(rect, this, 257, L"Exit to OS");\r
        }\r
+\r
        {\r
                core::rect<s32> rect(0, 0, 180, 240);\r
                rect = rect + v2s32(size.X/2 + 90, size.Y/2-rect.getHeight()/2);\r
@@ -172,6 +191,7 @@ void GUIPauseMenu::drawMenu()
 \r
 bool GUIPauseMenu::OnEvent(const SEvent& event)\r
 {\r
+\r
        if(event.EventType==EET_KEY_INPUT_EVENT)\r
        {\r
                if(event.KeyInput.PressedDown)\r
@@ -209,6 +229,10 @@ bool GUIPauseMenu::OnEvent(const SEvent& event)
                                quitMenu();\r
                                // ALWAYS return immediately after quitMenu()\r
                                return true;\r
+                       case 261:\r
+                               quitMenu();\r
+                               m_gamecallback->changePassword();\r
+                               return true;\r
                        case 260: // disconnect\r
                                m_gamecallback->disconnect();\r
                                quitMenu();\r
index 22cb65b2ceb13aa78804a112ec29e8d0216900ce..64e3c71f1d45a349aae990b25d1ab6fde1390476 100644 (file)
@@ -28,6 +28,7 @@ class IGameCallback
 public:\r
        virtual void exitToOS() = 0;\r
        virtual void disconnect() = 0;\r
+       virtual void changePassword() = 0;\r
 };\r
 \r
 class GUIPauseMenu : public GUIModalMenu\r
index c3b0757320c7061cea3de1f368b58ea6919d551e..2913d019daf6c6b055f2c8bad0a320cc0c9b0ee6 100644 (file)
@@ -353,8 +353,6 @@ Making it more portable:
 #include "materials.h"\r
 #include "game.h"\r
 #include "keycode.h"\r
-#include "sha1.h"\r
-#include "base64.h"\r
 \r
 // This makes textures\r
 ITextureSource *g_texturesource = NULL;\r
@@ -1468,24 +1466,7 @@ int main(int argc, char *argv[])
 \r
                                playername = wide_to_narrow(menudata.name);\r
 \r
-                               // Get an sha-1 hash of the player's name combined with\r
-                               // the password entered. That's what the server uses as\r
-                               // their password. (Exception : if the password field is\r
-                               // blank, we send a blank password - this is for backwards\r
-                               // compatibility with password-less players).\r
-                               if(menudata.password.length() > 0)\r
-                               {\r
-                                               std::string slt=playername + wide_to_narrow(menudata.password);\r
-                                               SHA1 *sha1 = new SHA1();\r
-                                               sha1->addBytes(slt.c_str(), slt.length());\r
-                                               unsigned char *digest = sha1->getDigest();\r
-                                               password = base64_encode(digest, 20);\r
-                                               free(digest);\r
-                               }\r
-                               else\r
-                               {\r
-                                               password = "";\r
-                               }\r
+                               password = translatePassword(playername, menudata.password);\r
 \r
                                address = wide_to_narrow(menudata.address);\r
                                int newport = stoi(wide_to_narrow(menudata.port));\r
index c8ac7ccf18c7cf228c6319d67fda7a277107d2a5..fcf150f874fea51c81c64976aad7bc6486827fa1 100644 (file)
@@ -119,6 +119,7 @@ class MainGameCallback : public IGameCallback
 public:
        MainGameCallback(IrrlichtDevice *a_device):
                disconnect_requested(false),
+               changepassword_requested(false),
                device(a_device)
        {
        }
@@ -133,7 +134,13 @@ public:
                disconnect_requested = true;
        }
 
+       virtual void changePassword()
+       {
+               changepassword_requested = true;
+       }
+
        bool disconnect_requested;
+       bool changepassword_requested;
        IrrlichtDevice *device;
 };
 
index 84f9a28e08f6d761a9a9a19799e7524c2cbba6e8..5c03ea8f6ffd7a9c810cc440a01ed5f3d58890be 100644 (file)
@@ -3004,6 +3004,31 @@ void Server::ProcessData(u8 *data, u32 datasize, u16 peer_id)
 
                SendPlayerHP(player);
        }
+       else if(command == TOSERVER_PASSWORD)
+       {
+               /*
+                       [0] u16 TOSERVER_PASSWORD
+                       [2] u8[28] old password
+                       [30] u8[28] new password
+               */
+
+               if(datasize != 2+PASSWORD_SIZE*2)
+                       return;
+               char password[PASSWORD_SIZE];
+               for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+                       password[i] = data[2+i];
+               password[PASSWORD_SIZE-1] = 0;
+               if(strcmp(player->getPassword(),password))
+               {
+                       // Wrong old password supplied!!
+                       SendChatMessage(peer_id, L"Invalid old password supplied. Password NOT changed.");
+                       return;
+               }
+               for(u32 i=0; i<PASSWORD_SIZE-1; i++)
+                       password[i] = data[30+i];
+               player->updatePassword(password);
+               SendChatMessage(peer_id, L"Password change successful");
+       }
        else
        {
                derr_server<<"WARNING: Server::ProcessData(): Ignoring "
index fc657b27bd63bd7fbf06751d3b3d202995e0b4d6..186881c5acc2ba59a794301f457248a202a2a4d4 100644 (file)
@@ -23,6 +23,8 @@ with this program; if not, write to the Free Software Foundation, Inc.,
 
 #include "utility.h"
 #include "gettime.h"
+#include "sha1.h"
+#include "base64.h"
 
 TimeTaker::TimeTaker(const char *name, u32 *result)
 {
@@ -217,3 +219,24 @@ bool isBlockInSight(v3s16 blockpos_b, v3f camera_pos, v3f camera_dir, f32 range,
        return true;
 }
 
+// Get an sha-1 hash of the player's name combined with
+// the password entered. That's what the server uses as
+// their password. (Exception : if the password field is
+// blank, we send a blank password - this is for backwards
+// compatibility with password-less players).
+std::string translatePassword(std::string playername, std::wstring password)
+{
+       if(password.length() == 0)
+               return "";
+
+       std::string slt=playername + wide_to_narrow(password);
+       SHA1 *sha1 = new SHA1();
+       sha1->addBytes(slt.c_str(), slt.length());
+       unsigned char *digest = sha1->getDigest();
+       std::string pwd = base64_encode(digest, 20);
+       free(digest);
+       return pwd;
+}
+
+
+
index f32dc3acfce4103749157b0304a479ea8617bad2..c7513e94d807a72e0901e89259377fefed3a6ecf 100644 (file)
@@ -2112,6 +2112,7 @@ protected:
        float m_accumulator;
 };
 
+std::string translatePassword(std::string playername, std::wstring password);
 
 #endif