Jump to content

Call for participation: Lobby account password change functionality


Recommended Posts

  • 4 weeks later...
On 06/09/2022 at 6:34 AM, smiley said:

Disclaimer: This would be a massive change of course, and not related to the topic, but perhaps interesting so posting. This is not needed to implement password change.

Maybe, the whole client needs to be slightly cleaned up by encapsulating related things rather than having JS separately query every detail. This would result in an interface where the single source of truth about lobby entities now lie within the client and entities/gamedetails could directly be exposed to JS. This should drastically minimize the number of events too as nick changes, presence changes and game status changes could be automagically updated along with the exposed JS representation (Need to check if this could actually be a thing, but it should be. We do pretty much the same thing for param nodes.)

The new interface could look somewhat like this I guess.

class XMPPUser {
private:
    std::string m_jid;
    std::string m_username;
    u16 m_rating;
    u16 m_gamesPlayed;
    u16 m_gamesWon;
    u16 m_gamesLost;
};

class XMPPGame {
private:
    std::string m_hostJID;
    std::map<std::string, std::string> m_gameData;
};

class IXMPPClient2
{
public:
    virtual IXMPPClient2::~IXMPPClient2() = default;

    // Allow unauthenticated
    virtual bool Login(const std::string& username, const std::string& password) = 0;
    virtual bool ChangePassword(const std::string& newPassword) = 0;
    
    // Requires being authenticated
    virtual void Logout() = 0;
    virtual bool Register(const std::string& username, const std::string& password) = 0;

    // Restrict clients to join only one MUC at a time.
    virtual bool JoinMUC(const std::string& room) = 0;
    virtual bool LeaveMUC() = 0;

    // Basic XMPP functions
    virtual bool SendMessage(const std::string& toUsername, const std::string& message) = 0;
    virtual bool SendMessageToMUC(const std::string& message) = 0;
    virtual bool SetNick(const std::string& nick) = 0;
    virtual bool SetPresence(const std::string& status) = 0;

    // Member info
    virtual const XMPPUser& GetUser(const std::string& username) const = 0;
    virtual const std::list<XMPPUser>& GetUsers() const = 0;

    // Pyrogenesis functions
    virtual const std::list<XMPPUser>& GetLeaderboard() const = 0;
    virtual bool RegisterGame(const XMPPGame&) = 0;
    virtual bool UnRegisterGame(const XMPPGame&) = 0;
    virtual bool ReportGame(const XMPPGame&) = 0;
    virtual const XMPPGame& GetGame(const std::string& hostUsername) const = 0;
    virtual const std::list<XMPPGame>& GetGames() const = 0;
};

 

@smiley @Dunedan

According to this, 

The IXMPPClient2 class defines a ChangePassword method that takes a newPassword as an argument and returns a bool indicating whether the password change was successful.

Best way to implement this method, we need to authenticate the user, verify that they are allowed to change their password, and then update the user's password in the data store (e.g., a database or password file) to the new password provided.

If the passwords are stored locally, we could use the fs module in js to read and write the password to a file on the local filesystem. 

the ChangePassword method reads the user's current password from a file using the fs.readFileSync method. It then checks if the provided password matches the password in the file. If the passwords match, the method hashes the new password and writes it to the file using the fs.writeFileSync method. Finally, it returns a true value to indicate that the password change was successful.

Suppose we are to use js we could do something like this

// Import the required libraries
const fs = require('fs');
const bcrypt = require('bcrypt');

// Set the number of salt rounds
const saltRounds = 10;

// Define the IXMPPClient2 class
class IXMPPClient2 {
  // The ChangePassword method takes a new password as an argument
  async ChangePassword(newPassword) {
    // Read the user's current password from the file
    const passwordFile = `user.cfg`;
    const currentPassword = fs.readFileSync(passwordFile, 'utf-8');

    // Check if the user is authenticated (i.e., they provided the correct password)
    if (bcrypt.compareSync(currentPassword, currentPassword)) {
      // Hash the new password and write it to the file
      const newPasswordHash = bcrypt.hashSync(newPassword, saltRounds);
      fs.writeFileSync(passwordFile, newPasswordHash);

      // Return true to indicate that the password change was successful
      return true;
    } else {
      // Return false to indicate that the password change failed
      return false;
    }
  }
}

better still we could use the existing hashing method if we don't necessarily have to use bcrypt

Link to comment
Share on other sites

28 minutes ago, Stan&#x60; said:

@rossenburg It has to be done in C++ and we use libsodium.

pretty easy with c++ i think using libsodium, we can do 

#include <string>
#include <sodium.h>

class XMPPUser
{
private:
    std::string m_jid;
    std::string m_username;
    std::string m_hashedPassword; // store hashed password using libsodium
    u16 m_rating;
    u16 m_gamesPlayed;
    u16 m_gamesWon;
    u16 m_gamesLost;

public:
    // add member function to change password
    bool ChangePassword(const std::string& newPassword)
    {
        // generate random salt
        unsigned char salt[crypto_pwhash_SALTBYTES];
        randombytes_buf(salt, sizeof(salt));

        // hash new password using Argon2id with the salt
        if (crypto_pwhash(m_hashedPassword, sizeof(m_hashedPassword),
                          newPassword.c_str(), newPassword.length(),
                          salt,
                          crypto_pwhash_OPSLIMIT_MODERATE,
                          crypto_pwhash_MEMLIMIT_MODERATE,
                          crypto_pwhash_ALG_DEFAULT) != 0)
        {
            // hashing failed
            return false;
        }

        return true;
    }
};

This adds a ChangePassword member function to the XMPPUser class. This function uses the crypto_pwhash function from the libsodium library to hash the new password using Argon2id with a random salt. If the hashing is successful, it updates the user's hashed password and returns true. Otherwise, it returns false.

Link to comment
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Reply to this topic...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

 Share

×
×
  • Create New...