mirror of
https://github.com/Cockatrice/Cockatrice.git
synced 2026-09-21 00:55:09 -07:00
[Game] Allow judges to enter any game regardless of restrictions (#7315)
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Some checks are pending
CodeQL / Analyze (cpp) (push) Waiting to run
CodeQL / Analyze (actions) (push) Waiting to run
Build Desktop / Configure (push) Waiting to run
Build Desktop / Debian 13 (push) Blocked by required conditions
Build Desktop / Debian 12 (push) Blocked by required conditions
Build Desktop / Fedora 44 (push) Blocked by required conditions
Build Desktop / Fedora 43 (push) Blocked by required conditions
Build Desktop / Servatrice_Debian 12 (push) Blocked by required conditions
Build Desktop / Ubuntu 26.04 (push) Blocked by required conditions
Build Desktop / Ubuntu 24.04 (push) Blocked by required conditions
Build Desktop / Arch (push) Blocked by required conditions
Build Desktop / macOS 13 Intel (push) Blocked by required conditions
Build Desktop / macOS 14 (push) Blocked by required conditions
Build Desktop / macOS 15 (push) Blocked by required conditions
Build Desktop / macOS 26 Debug (push) Blocked by required conditions
Build Desktop / Windows 10 (push) Blocked by required conditions
Build Docker / Servatrice (arm) (push) Waiting to run
Build Docker / Servatrice (x86) (push) Waiting to run
Build Docker / Publish multi-platform Servatrice image (push) Blocked by required conditions
Co-authored-by: Lukas Brübach <Bruebach.Lukas@bdosecurity.de>
This commit is contained in:
parent
cb19922e55
commit
db2e159dca
6 changed files with 190 additions and 3 deletions
|
|
@ -369,7 +369,7 @@ void GameSelector::joinGame(const ServerInfo_Game &game, const bool asSpectator,
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
|
bool overrideRestrictions = tabSupervisor->canOverrideGameRestrictions();
|
||||||
|
|
||||||
// Joining a full game without override privileges silently becomes a
|
// Joining a full game without override privileges silently becomes a
|
||||||
// spectator join, so ask first instead of surprising the player.
|
// spectator join, so ask first instead of surprising the player.
|
||||||
|
|
@ -462,7 +462,7 @@ void GameSelector::enableButtonsForIndex(const QModelIndex ¤t)
|
||||||
}
|
}
|
||||||
|
|
||||||
const ServerInfo_Game &game = gameListModel->getGame(current.data(Qt::UserRole).toInt());
|
const ServerInfo_Game &game = gameListModel->getGame(current.data(Qt::UserRole).toInt());
|
||||||
bool overrideRestrictions = !tabSupervisor->getAdminLocked();
|
bool overrideRestrictions = tabSupervisor->canOverrideGameRestrictions();
|
||||||
|
|
||||||
spectateButton->setEnabled(game.spectators_allowed() || overrideRestrictions);
|
spectateButton->setEnabled(game.spectators_allowed() || overrideRestrictions);
|
||||||
joinButton->setEnabled(game.player_count() < game.max_players() || overrideRestrictions);
|
joinButton->setEnabled(game.player_count() < game.max_players() || overrideRestrictions);
|
||||||
|
|
|
||||||
|
|
@ -1451,6 +1451,11 @@ bool TabSupervisor::getAdminLocked() const
|
||||||
return tabAdmin->getLocked();
|
return tabAdmin->getLocked();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool TabSupervisor::canOverrideGameRestrictions() const
|
||||||
|
{
|
||||||
|
return !getAdminLocked() || (userInfo->user_level() & ServerInfo_User::IsJudge);
|
||||||
|
}
|
||||||
|
|
||||||
void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event)
|
void TabSupervisor::processNotifyUserEvent(const Event_NotifyUser &event)
|
||||||
{
|
{
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -171,6 +171,7 @@ public:
|
||||||
[[nodiscard]] QList<GameInviteOption> getGameInviteLinksForRoom(int roomId) const;
|
[[nodiscard]] QList<GameInviteOption> getGameInviteLinksForRoom(int roomId) const;
|
||||||
void sendInviteToUser(const QString &userName, const QString &inviteText);
|
void sendInviteToUser(const QString &userName, const QString &inviteText);
|
||||||
[[nodiscard]] bool getAdminLocked() const;
|
[[nodiscard]] bool getAdminLocked() const;
|
||||||
|
[[nodiscard]] bool canOverrideGameRestrictions() const;
|
||||||
void closeEvent(QCloseEvent *event) override;
|
void closeEvent(QCloseEvent *event) override;
|
||||||
bool switchToGameTabIfAlreadyExists(const int gameId);
|
bool switchToGameTabIfAlreadyExists(const int gameId);
|
||||||
static void actShowPopup(const QString &message);
|
static void actShowPopup(const QString &message);
|
||||||
|
|
|
||||||
|
|
@ -465,7 +465,7 @@ Response::ResponseCode Server_Game::checkJoin(ServerInfo_User *user,
|
||||||
if (asJudge && !(user->user_level() & ServerInfo_User::IsJudge)) {
|
if (asJudge && !(user->user_level() & ServerInfo_User::IsJudge)) {
|
||||||
return Response::RespUserLevelTooLow;
|
return Response::RespUserLevelTooLow;
|
||||||
}
|
}
|
||||||
if (!(overrideRestrictions && (user->user_level() & ServerInfo_User::IsModerator))) {
|
if (!(overrideRestrictions && (user->user_level() & (ServerInfo_User::IsModerator | ServerInfo_User::IsJudge)))) {
|
||||||
if ((_password != password) && !(spectator && !spectatorsNeedPassword)) {
|
if ((_password != password) && !(spectator && !spectatorsNeedPassword)) {
|
||||||
return Response::RespWrongPassword;
|
return Response::RespWrongPassword;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -12,6 +12,7 @@ add_test(NAME server_card_counter_test COMMAND server_card_counter_test)
|
||||||
add_test(NAME server_counter_test COMMAND server_counter_test)
|
add_test(NAME server_counter_test COMMAND server_counter_test)
|
||||||
add_test(NAME server_rate_limiter_test COMMAND server_rate_limiter_test)
|
add_test(NAME server_rate_limiter_test COMMAND server_rate_limiter_test)
|
||||||
add_test(NAME server_developer_role_test COMMAND server_developer_role_test)
|
add_test(NAME server_developer_role_test COMMAND server_developer_role_test)
|
||||||
|
add_test(NAME server_game_join_test COMMAND server_game_join_test)
|
||||||
add_test(NAME warning_categories_test COMMAND warning_categories_test)
|
add_test(NAME warning_categories_test COMMAND warning_categories_test)
|
||||||
add_test(NAME lag_monitor_test COMMAND lag_monitor_test)
|
add_test(NAME lag_monitor_test COMMAND lag_monitor_test)
|
||||||
add_test(NAME latency_tracker_test COMMAND latency_tracker_test)
|
add_test(NAME latency_tracker_test COMMAND latency_tracker_test)
|
||||||
|
|
@ -34,6 +35,7 @@ add_executable(server_card_counter_test server_card_counter_test.cpp)
|
||||||
add_executable(server_counter_test server_counter_test.cpp)
|
add_executable(server_counter_test server_counter_test.cpp)
|
||||||
add_executable(server_rate_limiter_test server_rate_limiter_test.cpp)
|
add_executable(server_rate_limiter_test server_rate_limiter_test.cpp)
|
||||||
add_executable(server_developer_role_test server_developer_role_test.cpp)
|
add_executable(server_developer_role_test server_developer_role_test.cpp)
|
||||||
|
add_executable(server_game_join_test server_game_join_test.cpp)
|
||||||
add_executable(warning_categories_test warning_categories_test.cpp)
|
add_executable(warning_categories_test warning_categories_test.cpp)
|
||||||
add_executable(lag_monitor_test ${CMAKE_SOURCE_DIR}/cockatrice/src/client/lag_monitor.cpp lag_monitor_test.cpp)
|
add_executable(lag_monitor_test ${CMAKE_SOURCE_DIR}/cockatrice/src/client/lag_monitor.cpp lag_monitor_test.cpp)
|
||||||
target_include_directories(lag_monitor_test PRIVATE ${CMAKE_SOURCE_DIR}/cockatrice/src)
|
target_include_directories(lag_monitor_test PRIVATE ${CMAKE_SOURCE_DIR}/cockatrice/src)
|
||||||
|
|
@ -87,6 +89,7 @@ if(NOT GTEST_FOUND)
|
||||||
add_dependencies(server_counter_test gtest)
|
add_dependencies(server_counter_test gtest)
|
||||||
add_dependencies(server_rate_limiter_test gtest)
|
add_dependencies(server_rate_limiter_test gtest)
|
||||||
add_dependencies(server_developer_role_test gtest)
|
add_dependencies(server_developer_role_test gtest)
|
||||||
|
add_dependencies(server_game_join_test gtest)
|
||||||
add_dependencies(warning_categories_test gtest)
|
add_dependencies(warning_categories_test gtest)
|
||||||
add_dependencies(lag_monitor_test gtest)
|
add_dependencies(lag_monitor_test gtest)
|
||||||
add_dependencies(latency_tracker_test gtest)
|
add_dependencies(latency_tracker_test gtest)
|
||||||
|
|
@ -127,6 +130,10 @@ target_link_libraries(
|
||||||
server_developer_role_test libcockatrice_network libcockatrice_rng Threads::Threads ${GTEST_BOTH_LIBRARIES}
|
server_developer_role_test libcockatrice_network libcockatrice_rng Threads::Threads ${GTEST_BOTH_LIBRARIES}
|
||||||
${TEST_QT_MODULES}
|
${TEST_QT_MODULES}
|
||||||
)
|
)
|
||||||
|
target_link_libraries(
|
||||||
|
server_game_join_test libcockatrice_network_server_remote libcockatrice_rng Threads::Threads ${GTEST_BOTH_LIBRARIES}
|
||||||
|
${TEST_QT_MODULES}
|
||||||
|
)
|
||||||
target_link_libraries(
|
target_link_libraries(
|
||||||
warning_categories_test libcockatrice_utility Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}
|
warning_categories_test libcockatrice_utility Threads::Threads ${GTEST_BOTH_LIBRARIES} ${TEST_QT_MODULES}
|
||||||
)
|
)
|
||||||
|
|
|
||||||
174
tests/server_game_join_test.cpp
Normal file
174
tests/server_game_join_test.cpp
Normal file
|
|
@ -0,0 +1,174 @@
|
||||||
|
/** @file server_game_join_test.cpp
|
||||||
|
* @brief Tests for the moderator/judge game-entry restriction override in Server_Game::checkJoin.
|
||||||
|
* @ingroup Tests
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include "game/server_game.h"
|
||||||
|
#include "server.h"
|
||||||
|
#include "server_database_interface.h"
|
||||||
|
#include "server_room.h"
|
||||||
|
|
||||||
|
#include <gtest/gtest.h>
|
||||||
|
#include <libcockatrice/protocol/pb/serverinfo_user.pb.h>
|
||||||
|
#include <libcockatrice/rng/rng_abstract.h>
|
||||||
|
|
||||||
|
RNG_Abstract *rng = nullptr; // referenced by the server_remote library
|
||||||
|
|
||||||
|
namespace
|
||||||
|
{
|
||||||
|
|
||||||
|
class MockDatabaseInterface : public Server_DatabaseInterface
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
AuthenticationResult checkUserPassword(Server_ProtocolHandler *,
|
||||||
|
const QString &,
|
||||||
|
const QString &,
|
||||||
|
const QString &,
|
||||||
|
QString &,
|
||||||
|
int &,
|
||||||
|
bool) override
|
||||||
|
{
|
||||||
|
return NotLoggedIn;
|
||||||
|
}
|
||||||
|
int getNextReplayId() override
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int getNextGameId() override
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
int getActiveUserCount(QString) override
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
ServerInfo_User getUserData(const QString &, bool) override
|
||||||
|
{
|
||||||
|
return ServerInfo_User();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class FakeServer : public Server
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
FakeServer()
|
||||||
|
{
|
||||||
|
setDatabaseInterface(new MockDatabaseInterface());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class GameJoinOverrideTest : public ::testing::Test
|
||||||
|
{
|
||||||
|
protected:
|
||||||
|
FakeServer server;
|
||||||
|
Server_Room room{0, 0, "", "", "", "", false, "", {}, &server};
|
||||||
|
ServerInfo_User creator;
|
||||||
|
ServerInfo_User plainUser;
|
||||||
|
ServerInfo_User unregisteredJudge;
|
||||||
|
ServerInfo_User moderator;
|
||||||
|
ServerInfo_User judge;
|
||||||
|
Server_Game *game = nullptr;
|
||||||
|
|
||||||
|
void SetUp() override
|
||||||
|
{
|
||||||
|
creator.set_name("creator");
|
||||||
|
creator.set_user_level(ServerInfo_User::IsUser | ServerInfo_User::IsRegistered);
|
||||||
|
plainUser.set_name("plain-user");
|
||||||
|
plainUser.set_user_level(ServerInfo_User::IsUser | ServerInfo_User::IsRegistered);
|
||||||
|
unregisteredJudge.set_name("unregistered-judge");
|
||||||
|
unregisteredJudge.set_user_level(ServerInfo_User::IsUser | ServerInfo_User::IsJudge);
|
||||||
|
moderator.set_name("moderator");
|
||||||
|
moderator.set_user_level(ServerInfo_User::IsUser | ServerInfo_User::IsRegistered |
|
||||||
|
ServerInfo_User::IsModerator);
|
||||||
|
judge.set_name("judge");
|
||||||
|
judge.set_user_level(ServerInfo_User::IsUser | ServerInfo_User::IsRegistered | ServerInfo_User::IsJudge);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TearDown() override
|
||||||
|
{
|
||||||
|
delete game;
|
||||||
|
}
|
||||||
|
|
||||||
|
Server_Game *makeGame(bool passwordProtected, bool onlyRegistered, bool onlyBuddies, bool spectatorsAllowed)
|
||||||
|
{
|
||||||
|
GameConfig config{.creatorInfo = creator,
|
||||||
|
.gameId = 1,
|
||||||
|
.description = QString(),
|
||||||
|
.password = passwordProtected ? "secret" : QString(),
|
||||||
|
.maxPlayers = 2,
|
||||||
|
.gameTypes = QList<int>(),
|
||||||
|
.onlyBuddies = onlyBuddies,
|
||||||
|
.onlyRegistered = onlyRegistered,
|
||||||
|
.spectatorsAllowed = spectatorsAllowed,
|
||||||
|
.spectatorsNeedPassword = true,
|
||||||
|
.spectatorsCanTalk = false,
|
||||||
|
.spectatorsSeeEverything = false,
|
||||||
|
.startingLifeTotal = 20,
|
||||||
|
.shareDecklistsOnLoad = false};
|
||||||
|
return new Server_Game(config, &room);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
TEST_F(GameJoinOverrideTest, StaffBypassPasswordRestriction)
|
||||||
|
{
|
||||||
|
game = makeGame(true, false, false, true);
|
||||||
|
|
||||||
|
// A plain user cannot override the password even with the override flag set.
|
||||||
|
EXPECT_EQ(game->checkJoin(&plainUser, "wrong", false, true, false), Response::RespWrongPassword);
|
||||||
|
// Moderators and judges may enter any game regardless of the password.
|
||||||
|
EXPECT_EQ(game->checkJoin(&moderator, "wrong", false, true, false), Response::RespOk);
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, "wrong", false, true, false), Response::RespOk);
|
||||||
|
// Without the override flag judges are still subject to the password.
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, "wrong", false, false, true), Response::RespWrongPassword);
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, "secret", false, false, true), Response::RespOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GameJoinOverrideTest, StaffBypassRegisteredOnlyRestriction)
|
||||||
|
{
|
||||||
|
game = makeGame(false, true, false, true);
|
||||||
|
|
||||||
|
// Without the override flag the only-registered restriction still applies.
|
||||||
|
EXPECT_EQ(game->checkJoin(&unregisteredJudge, QString(), false, false, false), Response::RespUserLevelTooLow);
|
||||||
|
// An unregistered judge may enter when overriding restrictions.
|
||||||
|
EXPECT_EQ(game->checkJoin(&unregisteredJudge, QString(), false, true, false), Response::RespOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GameJoinOverrideTest, StaffBypassBuddiesOnlyRestriction)
|
||||||
|
{
|
||||||
|
game = makeGame(false, false, true, true);
|
||||||
|
|
||||||
|
// A plain user who is not on the creator's buddy list gets rejected.
|
||||||
|
EXPECT_EQ(game->checkJoin(&plainUser, QString(), false, true, false), Response::RespOnlyBuddies);
|
||||||
|
// Moderators and judges bypass the buddies-only restriction.
|
||||||
|
EXPECT_EQ(game->checkJoin(&moderator, QString(), false, true, false), Response::RespOk);
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, QString(), false, true, false), Response::RespOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GameJoinOverrideTest, StaffBypassSpectatorsNotAllowedRestriction)
|
||||||
|
{
|
||||||
|
game = makeGame(false, false, false, false);
|
||||||
|
|
||||||
|
// A plain user cannot spectate when the game disallows spectators.
|
||||||
|
EXPECT_EQ(game->checkJoin(&plainUser, QString(), true, false, false), Response::RespSpectatorsNotAllowed);
|
||||||
|
// Moderators and judges may spectate any game regardless of the password
|
||||||
|
// and the spectator restriction.
|
||||||
|
EXPECT_EQ(game->checkJoin(&moderator, "wrong", true, true, false), Response::RespOk);
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, "wrong", true, true, false), Response::RespOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_F(GameJoinOverrideTest, JudgeOverrideDoesNotGrantJudgeJoinToPlainUser)
|
||||||
|
{
|
||||||
|
game = makeGame(false, false, false, true);
|
||||||
|
|
||||||
|
// joining with join_as_judge still requires the judge flag even when overriding.
|
||||||
|
EXPECT_EQ(game->checkJoin(&plainUser, QString(), false, true, true), Response::RespUserLevelTooLow);
|
||||||
|
EXPECT_EQ(game->checkJoin(&judge, QString(), false, true, true), Response::RespOk);
|
||||||
|
}
|
||||||
|
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
int main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
::testing::InitGoogleTest(&argc, argv);
|
||||||
|
return RUN_ALL_TESTS();
|
||||||
|
}
|
||||||
Loading…
Add table
Add a link
Reference in a new issue