Skip to content

Commit

Permalink
initial support for admins being allowed to perform host-only actions
Browse files Browse the repository at this point in the history
  • Loading branch information
maxsupermanhd committed Sep 27, 2024
1 parent 9045591 commit e5e2dd9
Show file tree
Hide file tree
Showing 7 changed files with 26 additions and 7 deletions.
4 changes: 4 additions & 0 deletions lib/netplay/netplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include "src/console.h"
#include "src/component.h" // FIXME: we need to handle this better
#include "src/modding.h" // FIXME: we need to handle this better
#include "src/multilobbycommands.h"

#include <time.h> // for stats
#include <physfs.h>
Expand Down Expand Up @@ -4293,9 +4294,12 @@ static void NETallowJoining()

NEThostPromoteTempSocketToPermanentPlayerConnection(i, index);

bool isAdminJoining = identityMatchesAdmin(joinRequestInfo.identity);

NETbeginEncode(NETnetQueue(index), NET_ACCEPTED);
NETuint8_t(&index);
NETuint32_t(&NetPlay.hostPlayer);
NETbool(&isAdminJoining);
NETend();

// First send info about players to newcomer.
Expand Down
1 change: 1 addition & 0 deletions lib/netplay/netplay.h
Original file line number Diff line number Diff line change
Expand Up @@ -316,6 +316,7 @@ struct NETPLAY
uint32_t hostPlayer; ///< Index of host in player array
bool bComms; ///< Actually do the comms?
bool isHost; ///< True if we are hosting the game
bool isAdmin; ///< True if we are promoted to admin by the host
bool isPortMappingEnabled; // if we want the automatic Port mapping setup routines to run
bool isHostAlive; /// if the host is still alive
char gamePassword[password_string_size]; //
Expand Down
12 changes: 7 additions & 5 deletions src/multiint.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1982,7 +1982,7 @@ static std::set<uint32_t> validPlayerIdxTargetsForPlayerPositionMove(uint32_t pl
for (uint32_t i = 0; i < game.maxPlayers; i++)
{
if (player != i
&& (NetPlay.isHost || !isHumanPlayer(i)) // host can move a player to any slot, player can only move to empty slots
&& (NetPlay.isHost || (!isHumanPlayer(i) || NetPlay.isAdmin)) // host/admin can move a player to any slot, player can only move to empty slots
&& !isSpectatorOnlySlot(i)) // target cannot be a spectator only slot (for player position changes)
{
validTargetPlayerIdx.insert(i);
Expand Down Expand Up @@ -2835,7 +2835,7 @@ bool recvPositionRequest(NETQUEUE queue)
return false;
}

if (whosResponsible(player) != queue.index)
if (whosResponsible(player) != queue.index && !senderHasLobbyCommandAdminPrivs(queue.index))
{
HandleBadParam("NET_POSITIONREQUEST given incorrect params.", player, queue.index);
return false;
Expand Down Expand Up @@ -3996,7 +3996,7 @@ class WzPlayerRow : public WIDGET
widget->colorButton->addOnClickHandler([playerIdx, titleUI](W_BUTTON& button){
auto strongTitleUI = titleUI.lock();
ASSERT_OR_RETURN(, strongTitleUI != nullptr, "Title UI is gone?");
if (playerIdx == selectedPlayer || NetPlay.isHost)
if (playerIdx == selectedPlayer || (NetPlay.isHost || NetPlay.isAdmin))
{
if (!NetPlay.players[playerIdx].isSpectator) // not a spectator
{
Expand Down Expand Up @@ -4031,11 +4031,13 @@ class WzPlayerRow : public WIDGET
widget->playerInfo->addOnClickHandler([playerIdx, titleUI](W_BUTTON& button){
auto strongTitleUI = titleUI.lock();
ASSERT_OR_RETURN(, strongTitleUI != nullptr, "Title UI is gone?");
if (playerIdx == selectedPlayer || NetPlay.isHost)
if (playerIdx == selectedPlayer || (NetPlay.isHost || NetPlay.isAdmin))
{
uint32_t player = playerIdx;
// host can move any player, clients can request to move themselves if there are available slots
if (((player == selectedPlayer && validPlayerIdxTargetsForPlayerPositionMove(player).size() > 0) || (NetPlay.players[player].allocated && NetPlay.isHost))
// admins can move people as if they are host
if (((player == selectedPlayer && validPlayerIdxTargetsForPlayerPositionMove(player).size() > 0) ||
(NetPlay.players[player].allocated && (NetPlay.isHost || NetPlay.isAdmin)))
&& !locked.position
&& player < MAX_PLAYERS
&& !isSpectatorOnlySlot(player))
Expand Down
9 changes: 8 additions & 1 deletion src/multilobbycommands.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,13 @@ bool removeLobbyAdminPublicKey(const std::string& publicKeyB64Str)
return lobbyAdminPublicKeys.erase(publicKeyB64Str) > 0;
}

// checks for specific identity being an admin
bool identityMatchesAdmin(const EcKey& identity) {
std::string senderIdentityHash = identity.publicHashString();
std::string senderPublicKeyB64 = base64Encode(identity.toBytes(EcKey::Public));
return lobbyAdminPublicKeys.count(senderPublicKeyB64) != 0 || lobbyAdminPublicHashStrings.count(senderIdentityHash) != 0;
}

// NOTE: **IMPORTANT** this should *NOT* be used for determining whether a sender has permission to execute admin commands
// (Use senderHasLobbyCommandAdminPrivs instead)
static bool senderApparentlyMatchesAdmin(uint32_t playerIdx)
Expand Down Expand Up @@ -86,7 +93,7 @@ static bool senderApparentlyMatchesAdmin(uint32_t playerIdx)
}

// **THIS** is the function that should be used to determine whether a sender currently has permission to execute admin commands
static bool senderHasLobbyCommandAdminPrivs(uint32_t playerIdx)
bool senderHasLobbyCommandAdminPrivs(uint32_t playerIdx)
{
if (playerIdx >= MAX_CONNECTED_PLAYERS)
{
Expand Down
3 changes: 3 additions & 0 deletions src/multilobbycommands.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,9 @@ void cmdInterfaceLogChatMsg(const NetworkTextMessage& message, const char* log_p

bool processChatLobbySlashCommands(const NetworkTextMessage& message, HostLobbyOperationsInterface& cmdInterface);

bool identityMatchesAdmin(const EcKey& identity);
bool senderHasLobbyCommandAdminPrivs(uint32_t playerIdx);

bool addLobbyAdminIdentityHash(const std::string& playerIdentityHash);
bool removeLobbyAdminIdentityHash(const std::string& playerIdentityHash);

Expand Down
3 changes: 2 additions & 1 deletion src/multiplay.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,7 @@ HandleMessageAction getMessageHandlingAction(NETQUEUE& queue, uint8_t type)
}

bool senderIsSpectator = NetPlay.players[queue.index].isSpectator;
bool senderIsAdmin = senderHasLobbyCommandAdminPrivs(queue.index);

if (type > NET_MIN_TYPE && type < NET_MAX_TYPE)
{
Expand All @@ -1053,7 +1054,7 @@ HandleMessageAction getMessageHandlingAction(NETQUEUE& queue, uint8_t type)
case NET_BEACONMSG:
case NET_TEAMREQUEST: // spectators should not be allowed to request a team / non-spectator slot status
case NET_POSITIONREQUEST:
if (senderIsSpectator)
if (senderIsSpectator && !senderIsAdmin)
{
return HandleMessageAction::Disallow_And_Kick_Sender;
}
Expand Down
1 change: 1 addition & 0 deletions src/screens/joiningscreen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1388,6 +1388,7 @@ void WzJoiningGameScreen_HandlerRoot::processJoining()
// Retrieve the player ID the game host arranged for us
NETuint8_t(&index);
NETuint32_t(&hostPlayer); // and the host player idx
NETbool(&NetPlay.isAdmin);
NETend();
NETpop(tmpJoiningQUEUE);

Expand Down

0 comments on commit e5e2dd9

Please sign in to comment.